| author | |
| committer | |
| log | fe660462837231353b846bf398637ca84f67bfc9 |
| tree | 37336cfcf44810d73d111a57207b843a01fd205f |
| parent | fe39ca01bcbee0077b21d5ddc2776df974e8c6d3 |
| parent | 39c7bd24e4f768b23074b8634ac637b175b7639f |
163 files changed, 8285 insertions(+), 3423 deletions(-)
README.md+29-24| ... | @@ -119,31 +119,22 @@ libc. Create demo games using Zig. | ... | @@ -119,31 +119,22 @@ libc. Create demo games using Zig. |
| 119 | [](https://travis-ci.org/zig-lang/zig) | 119 | [](https://travis-ci.org/zig-lang/zig) |
| 120 | [](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master) | 120 | [](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master) |
| 121 | 121 | ||
| 122 | ### Dependencies | 122 | ### Stage 1: Build Zig from C++ Source Code |
| 123 | 123 | ||
| 124 | #### Build Dependencies | 124 | #### Dependencies |
| 125 | |||
| 126 | These compile tools must be available on your system and are used to build | ||
| 127 | the Zig compiler itself: | ||
| 128 | 125 | ||
| 129 | ##### POSIX | 126 | ##### POSIX |
| 130 | 127 | ||
| 131 | * gcc >= 5.0.0 or clang >= 3.6.0 | 128 | * gcc >= 5.0.0 or clang >= 3.6.0 |
| 132 | * cmake >= 2.8.5 | 129 | * cmake >= 2.8.5 |
| 130 | * LLVM, Clang, LLD libraries == 6.x, compiled with the same gcc or clang version above | ||
| 133 | 131 | ||
| 134 | ##### Windows | 132 | ##### Windows |
| 135 | 133 | ||
| 136 | * Microsoft Visual Studio 2015 | 134 | * Microsoft Visual Studio 2015 |
| 135 | * LLVM, Clang, LLD libraries == 6.x, compiled with the same MSVC version above | ||
| 137 | 136 | ||
| 138 | #### Library Dependencies | 137 | #### Instructions |
| 139 | |||
| 140 | These libraries must be installed on your system, with the development files | ||
| 141 | available. The Zig compiler links against them. You have to use the same | ||
| 142 | compiler for these libraries as you do to compile Zig. | ||
| 143 | |||
| 144 | * LLVM, Clang, and LLD libraries == 6.x | ||
| 145 | |||
| 146 | ### Debug / Development Build | ||
| 147 | 138 | ||
| 148 | If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`, | 139 | If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`, |
| 149 | `ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to | 140 | `ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to |
| ... | @@ -158,7 +149,7 @@ make install | ... | @@ -158,7 +149,7 @@ make install |
| 158 | ./zig build --build-file ../build.zig test | 149 | ./zig build --build-file ../build.zig test |
| 159 | ``` | 150 | ``` |
| 160 | 151 | ||
| 161 | #### MacOS | 152 | ##### MacOS |
| 162 | 153 | ||
| 163 | `ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused. | 154 | `ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused. |
| 164 | 155 | ||
| ... | @@ -172,21 +163,35 @@ make install | ... | @@ -172,21 +163,35 @@ make install |
| 172 | ./zig build --build-file ../build.zig test | 163 | ./zig build --build-file ../build.zig test |
| 173 | ``` | 164 | ``` |
| 174 | 165 | ||
| 175 | #### Windows | 166 | ##### Windows |
| 176 | 167 | ||
| 177 | See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows | 168 | See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows |
| 178 | 169 | ||
| 179 | ### Release / Install Build | 170 | ### Stage 2: Build Self-Hosted Zig from Zig Source Code |
| 180 | 171 | ||
| 181 | Once installed, `ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_INCLUDE_DIR` can be overridden | 172 | *Note: Stage 2 compiler is not complete. Beta users of Zig should use the |
| 182 | by the `--libc-lib-dir` and `--libc-include-dir` parameters to the zig binary. | 173 | Stage 1 compiler for now.* |
| 174 | |||
| 175 | Dependencies are the same as Stage 1, except now you have a working zig compiler. | ||
| 183 | 176 | ||
| 184 | ``` | 177 | ``` |
| 185 | mkdir build | 178 | bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install |
| 186 | cd build | 179 | ``` |
| 187 | cmake .. -DCMAKE_BUILD_TYPE=Release -DZIG_LIBC_LIB_DIR=/some/path -DZIG_LIBC_INCLUDE_DIR=/some/path -DZIG_LIBC_STATIC_INCLUDE_DIR=/some/path | 180 | |
| 188 | make | 181 | ### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler |
| 189 | sudo make install | 182 | |
| 183 | This is the actual compiler binary that we will install to the system. | ||
| 184 | |||
| 185 | #### Debug / Development Build | ||
| 186 | |||
| 187 | ``` | ||
| 188 | ./stage2/bin/zig build --build-file ../build.zig --prefix $(pwd)/stage3 install | ||
| 189 | ``` | ||
| 190 | |||
| 191 | #### Release / Install Build | ||
| 192 | |||
| 193 | ``` | ||
| 194 | ./stage2/bin/zig build --build-file ../build.zig install -Drelease-fast | ||
| 190 | ``` | 195 | ``` |
| 191 | 196 | ||
| 192 | ### Test Coverage | 197 | ### Test Coverage |
build.zig+218-8| ... | @@ -1,6 +1,13 @@ | ... | @@ -1,6 +1,13 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const std = @import("std"); |
| 2 | const Builder = std.build.Builder; | ||
| 2 | const tests = @import("test/tests.zig"); | 3 | const tests = @import("test/tests.zig"); |
| 3 | const os = @import("std").os; | 4 | const os = std.os; |
| 5 | const BufMap = std.BufMap; | ||
| 6 | const warn = std.debug.warn; | ||
| 7 | const mem = std.mem; | ||
| 8 | const ArrayList = std.ArrayList; | ||
| 9 | const Buffer = std.Buffer; | ||
| 10 | const io = std.io; | ||
| 4 | 11 | ||
| 5 | pub fn build(b: &Builder) { | 12 | pub fn build(b: &Builder) { |
| 6 | const mode = b.standardReleaseOptions(); | 13 | const mode = b.standardReleaseOptions(); |
| ... | @@ -25,14 +32,18 @@ pub fn build(b: &Builder) { | ... | @@ -25,14 +32,18 @@ pub fn build(b: &Builder) { |
| 25 | docs_step.dependOn(&docgen_cmd.step); | 32 | docs_step.dependOn(&docgen_cmd.step); |
| 26 | docs_step.dependOn(&docgen_home_cmd.step); | 33 | docs_step.dependOn(&docgen_home_cmd.step); |
| 27 | 34 | ||
| 28 | var exe = b.addExecutable("zig", "src-self-hosted/main.zig"); | 35 | if (findLLVM(b)) |llvm| { |
| 29 | exe.setBuildMode(mode); | 36 | var exe = b.addExecutable("zig", "src-self-hosted/main.zig"); |
| 30 | exe.linkSystemLibrary("c"); | 37 | exe.setBuildMode(mode); |
| 38 | exe.linkSystemLibrary("c"); | ||
| 39 | dependOnLib(exe, llvm); | ||
| 31 | 40 | ||
| 32 | b.default_step.dependOn(&exe.step); | 41 | b.default_step.dependOn(&exe.step); |
| 33 | b.default_step.dependOn(docs_step); | 42 | b.default_step.dependOn(docs_step); |
| 34 | 43 | ||
| 35 | b.installArtifact(exe); | 44 | b.installArtifact(exe); |
| 45 | installStdLib(b); | ||
| 46 | } | ||
| 36 | 47 | ||
| 37 | 48 | ||
| 38 | const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter"); | 49 | const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter"); |
| ... | @@ -53,6 +64,10 @@ pub fn build(b: &Builder) { | ... | @@ -53,6 +64,10 @@ pub fn build(b: &Builder) { |
| 53 | "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests", | 64 | "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests", |
| 54 | with_lldb)); | 65 | with_lldb)); |
| 55 | 66 | ||
| 67 | test_step.dependOn(tests.addPkgTests(b, test_filter, | ||
| 68 | "src-self-hosted/main.zig", "fmt", "Run the fmt tests", | ||
| 69 | with_lldb)); | ||
| 70 | |||
| 56 | test_step.dependOn(tests.addCompareOutputTests(b, test_filter)); | 71 | test_step.dependOn(tests.addCompareOutputTests(b, test_filter)); |
| 57 | test_step.dependOn(tests.addBuildExampleTests(b, test_filter)); | 72 | test_step.dependOn(tests.addBuildExampleTests(b, test_filter)); |
| 58 | test_step.dependOn(tests.addCompileErrorTests(b, test_filter)); | 73 | test_step.dependOn(tests.addCompileErrorTests(b, test_filter)); |
| ... | @@ -60,3 +75,198 @@ pub fn build(b: &Builder) { | ... | @@ -60,3 +75,198 @@ pub fn build(b: &Builder) { |
| 60 | test_step.dependOn(tests.addDebugSafetyTests(b, test_filter)); | 75 | test_step.dependOn(tests.addDebugSafetyTests(b, test_filter)); |
| 61 | test_step.dependOn(tests.addTranslateCTests(b, test_filter)); | 76 | test_step.dependOn(tests.addTranslateCTests(b, test_filter)); |
| 62 | } | 77 | } |
| 78 | |||
| 79 | fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) { | ||
| 80 | for (dep.libdirs.toSliceConst()) |lib_dir| { | ||
| 81 | lib_exe_obj.addLibPath(lib_dir); | ||
| 82 | } | ||
| 83 | for (dep.libs.toSliceConst()) |lib| { | ||
| 84 | lib_exe_obj.linkSystemLibrary(lib); | ||
| 85 | } | ||
| 86 | for (dep.includes.toSliceConst()) |include_path| { | ||
| 87 | lib_exe_obj.addIncludeDir(include_path); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | const LibraryDep = struct { | ||
| 92 | libdirs: ArrayList([]const u8), | ||
| 93 | libs: ArrayList([]const u8), | ||
| 94 | includes: ArrayList([]const u8), | ||
| 95 | }; | ||
| 96 | |||
| 97 | fn findLLVM(b: &Builder) -> ?LibraryDep { | ||
| 98 | const llvm_config_exe = b.findProgram( | ||
| 99 | [][]const u8{"llvm-config-5.0", "llvm-config"}, | ||
| 100 | [][]const u8{ | ||
| 101 | "/usr/local/opt/llvm@5/bin", | ||
| 102 | "/mingw64/bin", | ||
| 103 | "/c/msys64/mingw64/bin", | ||
| 104 | "c:/msys64/mingw64/bin", | ||
| 105 | "C:/Libraries/llvm-5.0.0/bin", | ||
| 106 | }) %% |err| | ||
| 107 | { | ||
| 108 | warn("unable to find llvm-config: {}\n", err); | ||
| 109 | return null; | ||
| 110 | }; | ||
| 111 | const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"}); | ||
| 112 | const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"}); | ||
| 113 | const libdir_output = b.exec([][]const u8{llvm_config_exe, "--libdir"}); | ||
| 114 | |||
| 115 | var result = LibraryDep { | ||
| 116 | .libs = ArrayList([]const u8).init(b.allocator), | ||
| 117 | .includes = ArrayList([]const u8).init(b.allocator), | ||
| 118 | .libdirs = ArrayList([]const u8).init(b.allocator), | ||
| 119 | }; | ||
| 120 | { | ||
| 121 | var it = mem.split(libs_output, " \n"); | ||
| 122 | while (it.next()) |lib_arg| { | ||
| 123 | if (mem.startsWith(u8, lib_arg, "-l")) { | ||
| 124 | %%result.libs.append(lib_arg[2..]); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | } | ||
| 128 | { | ||
| 129 | var it = mem.split(includes_output, " \n"); | ||
| 130 | while (it.next()) |include_arg| { | ||
| 131 | if (mem.startsWith(u8, include_arg, "-I")) { | ||
| 132 | %%result.includes.append(include_arg[2..]); | ||
| 133 | } else { | ||
| 134 | %%result.includes.append(include_arg); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | } | ||
| 138 | { | ||
| 139 | var it = mem.split(libdir_output, " \n"); | ||
| 140 | while (it.next()) |libdir| { | ||
| 141 | if (mem.startsWith(u8, libdir, "-L")) { | ||
| 142 | %%result.libdirs.append(libdir[2..]); | ||
| 143 | } else { | ||
| 144 | %%result.libdirs.append(libdir); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
| 148 | return result; | ||
| 149 | } | ||
| 150 | |||
| 151 | pub fn installStdLib(b: &Builder) { | ||
| 152 | const stdlib_files = []const []const u8 { | ||
| 153 | "array_list.zig", | ||
| 154 | "base64.zig", | ||
| 155 | "buf_map.zig", | ||
| 156 | "buf_set.zig", | ||
| 157 | "buffer.zig", | ||
| 158 | "build.zig", | ||
| 159 | "c/darwin.zig", | ||
| 160 | "c/index.zig", | ||
| 161 | "c/linux.zig", | ||
| 162 | "c/windows.zig", | ||
| 163 | "cstr.zig", | ||
| 164 | "debug.zig", | ||
| 165 | "dwarf.zig", | ||
| 166 | "elf.zig", | ||
| 167 | "empty.zig", | ||
| 168 | "endian.zig", | ||
| 169 | "fmt/errol/enum3.zig", | ||
| 170 | "fmt/errol/index.zig", | ||
| 171 | "fmt/errol/lookup.zig", | ||
| 172 | "fmt/index.zig", | ||
| 173 | "hash_map.zig", | ||
| 174 | "heap.zig", | ||
| 175 | "index.zig", | ||
| 176 | "io.zig", | ||
| 177 | "linked_list.zig", | ||
| 178 | "math/acos.zig", | ||
| 179 | "math/acosh.zig", | ||
| 180 | "math/asin.zig", | ||
| 181 | "math/asinh.zig", | ||
| 182 | "math/atan.zig", | ||
| 183 | "math/atan2.zig", | ||
| 184 | "math/atanh.zig", | ||
| 185 | "math/cbrt.zig", | ||
| 186 | "math/ceil.zig", | ||
| 187 | "math/copysign.zig", | ||
| 188 | "math/cos.zig", | ||
| 189 | "math/cosh.zig", | ||
| 190 | "math/exp.zig", | ||
| 191 | "math/exp2.zig", | ||
| 192 | "math/expm1.zig", | ||
| 193 | "math/expo2.zig", | ||
| 194 | "math/fabs.zig", | ||
| 195 | "math/floor.zig", | ||
| 196 | "math/fma.zig", | ||
| 197 | "math/frexp.zig", | ||
| 198 | "math/hypot.zig", | ||
| 199 | "math/ilogb.zig", | ||
| 200 | "math/index.zig", | ||
| 201 | "math/inf.zig", | ||
| 202 | "math/isfinite.zig", | ||
| 203 | "math/isinf.zig", | ||
| 204 | "math/isnan.zig", | ||
| 205 | "math/isnormal.zig", | ||
| 206 | "math/ln.zig", | ||
| 207 | "math/log.zig", | ||
| 208 | "math/log10.zig", | ||
| 209 | "math/log1p.zig", | ||
| 210 | "math/log2.zig", | ||
| 211 | "math/modf.zig", | ||
| 212 | "math/nan.zig", | ||
| 213 | "math/pow.zig", | ||
| 214 | "math/round.zig", | ||
| 215 | "math/scalbn.zig", | ||
| 216 | "math/signbit.zig", | ||
| 217 | "math/sin.zig", | ||
| 218 | "math/sinh.zig", | ||
| 219 | "math/sqrt.zig", | ||
| 220 | "math/tan.zig", | ||
| 221 | "math/tanh.zig", | ||
| 222 | "math/trunc.zig", | ||
| 223 | "mem.zig", | ||
| 224 | "net.zig", | ||
| 225 | "os/child_process.zig", | ||
| 226 | "os/darwin.zig", | ||
| 227 | "os/darwin_errno.zig", | ||
| 228 | "os/get_user_id.zig", | ||
| 229 | "os/index.zig", | ||
| 230 | "os/linux.zig", | ||
| 231 | "os/linux_errno.zig", | ||
| 232 | "os/linux_i386.zig", | ||
| 233 | "os/linux_x86_64.zig", | ||
| 234 | "os/path.zig", | ||
| 235 | "os/windows/error.zig", | ||
| 236 | "os/windows/index.zig", | ||
| 237 | "os/windows/util.zig", | ||
| 238 | "rand.zig", | ||
| 239 | "sort.zig", | ||
| 240 | "special/bootstrap.zig", | ||
| 241 | "special/bootstrap_lib.zig", | ||
| 242 | "special/build_file_template.zig", | ||
| 243 | "special/build_runner.zig", | ||
| 244 | "special/builtin.zig", | ||
| 245 | "special/compiler_rt/aulldiv.zig", | ||
| 246 | "special/compiler_rt/aullrem.zig", | ||
| 247 | "special/compiler_rt/comparetf2.zig", | ||
| 248 | "special/compiler_rt/fixuint.zig", | ||
| 249 | "special/compiler_rt/fixunsdfdi.zig", | ||
| 250 | "special/compiler_rt/fixunsdfsi.zig", | ||
| 251 | "special/compiler_rt/fixunsdfti.zig", | ||
| 252 | "special/compiler_rt/fixunssfdi.zig", | ||
| 253 | "special/compiler_rt/fixunssfsi.zig", | ||
| 254 | "special/compiler_rt/fixunssfti.zig", | ||
| 255 | "special/compiler_rt/fixunstfdi.zig", | ||
| 256 | "special/compiler_rt/fixunstfsi.zig", | ||
| 257 | "special/compiler_rt/fixunstfti.zig", | ||
| 258 | "special/compiler_rt/index.zig", | ||
| 259 | "special/compiler_rt/udivmod.zig", | ||
| 260 | "special/compiler_rt/udivmoddi4.zig", | ||
| 261 | "special/compiler_rt/udivmodti4.zig", | ||
| 262 | "special/compiler_rt/udivti3.zig", | ||
| 263 | "special/compiler_rt/umodti3.zig", | ||
| 264 | "special/panic.zig", | ||
| 265 | "special/test_runner.zig", | ||
| 266 | }; | ||
| 267 | for (stdlib_files) |stdlib_file| { | ||
| 268 | const src_path = %%os.path.join(b.allocator, "std", stdlib_file); | ||
| 269 | const dest_path = %%os.path.join(b.allocator, "lib", "zig", "std", stdlib_file); | ||
| 270 | b.installFile(src_path, dest_path); | ||
| 271 | } | ||
| 272 | } |
doc/docgen.zig+2-2| ... | @@ -42,14 +42,14 @@ const State = enum { | ... | @@ -42,14 +42,14 @@ const State = enum { |
| 42 | 42 | ||
| 43 | // TODO look for code segments | 43 | // TODO look for code segments |
| 44 | 44 | ||
| 45 | fn gen(in: &io.InStream, out: &const io.OutStream) { | 45 | fn gen(in: &io.InStream, out: &io.OutStream) { |
| 46 | var state = State.Start; | 46 | var state = State.Start; |
| 47 | while (true) { | 47 | while (true) { |
| 48 | const byte = in.readByte() %% |err| { | 48 | const byte = in.readByte() %% |err| { |
| 49 | if (err == error.EndOfStream) { | 49 | if (err == error.EndOfStream) { |
| 50 | return; | 50 | return; |
| 51 | } | 51 | } |
| 52 | std.debug.panic("{}", err) | 52 | std.debug.panic("{}", err); |
| 53 | }; | 53 | }; |
| 54 | switch (state) { | 54 | switch (state) { |
| 55 | State.Start => switch (byte) { | 55 | State.Start => switch (byte) { |
doc/langref.html.in+21-20| ... | @@ -136,6 +136,7 @@ | ... | @@ -136,6 +136,7 @@ |
| 136 | <li><a href="#builtin-divFloor">@divFloor</a></li> | 136 | <li><a href="#builtin-divFloor">@divFloor</a></li> |
| 137 | <li><a href="#builtin-divTrunc">@divTrunc</a></li> | 137 | <li><a href="#builtin-divTrunc">@divTrunc</a></li> |
| 138 | <li><a href="#builtin-embedFile">@embedFile</a></li> | 138 | <li><a href="#builtin-embedFile">@embedFile</a></li> |
| 139 | <li><a href="#builtin-export">@export</a></li> | ||
| 139 | <li><a href="#builtin-tagName">@tagName</a></li> | 140 | <li><a href="#builtin-tagName">@tagName</a></li> |
| 140 | <li><a href="#builtin-EnumTagType">@EnumTagType</a></li> | 141 | <li><a href="#builtin-EnumTagType">@EnumTagType</a></li> |
| 141 | <li><a href="#builtin-errorName">@errorName</a></li> | 142 | <li><a href="#builtin-errorName">@errorName</a></li> |
| ... | @@ -3020,14 +3021,13 @@ const assert = @import("std").debug.assert;</code></pre> | ... | @@ -3020,14 +3021,13 @@ const assert = @import("std").debug.assert;</code></pre> |
| 3020 | <pre><code class="zig">const assert = @import("std").debug.assert; | 3021 | <pre><code class="zig">const assert = @import("std").debug.assert; |
| 3021 | 3022 | ||
| 3022 | // Functions are declared like this | 3023 | // Functions are declared like this |
| 3023 | // The last expression in the function can be used as the return value. | ||
| 3024 | fn add(a: i8, b: i8) -&gt; i8 { | 3024 | fn add(a: i8, b: i8) -&gt; i8 { |
| 3025 | if (a == 0) { | 3025 | if (a == 0) { |
| 3026 | // You can still return manually if needed. | 3026 | // You can still return manually if needed. |
| 3027 | return b; | 3027 | return b; |
| 3028 | } | 3028 | } |
| 3029 | 3029 | ||
| 3030 | a + b | 3030 | return a + b; |
| 3031 | } | 3031 | } |
| 3032 | 3032 | ||
| 3033 | // The export specifier makes a function externally visible in the generated | 3033 | // The export specifier makes a function externally visible in the generated |
| ... | @@ -4368,6 +4368,11 @@ test.zig:6:2: error: found compile log statement | ... | @@ -4368,6 +4368,11 @@ test.zig:6:2: error: found compile log statement |
| 4368 | <ul> | 4368 | <ul> |
| 4369 | <li><a href="#builtin-import">@import</a></li> | 4369 | <li><a href="#builtin-import">@import</a></li> |
| 4370 | </ul> | 4370 | </ul> |
| 4371 | <h3 id="builtin-export">@export</h3> | ||
| 4372 | <pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) -&gt; []const u8</code></pre> | ||
| 4373 | <p> | ||
| 4374 | Creates a symbol in the output object file. | ||
| 4375 | </p> | ||
| 4371 | <h3 id="builtin-tagName">@tagName</h3> | 4376 | <h3 id="builtin-tagName">@tagName</h3> |
| 4372 | <pre><code class="zig">@tagName(value: var) -&gt; []const u8</code></pre> | 4377 | <pre><code class="zig">@tagName(value: var) -&gt; []const u8</code></pre> |
| 4373 | <p> | 4378 | <p> |
| ... | @@ -5815,13 +5820,15 @@ TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestD | ... | @@ -5815,13 +5820,15 @@ TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestD |
| 5815 | 5820 | ||
| 5816 | TestDecl = "test" String Block | 5821 | TestDecl = "test" String Block |
| 5817 | 5822 | ||
| 5818 | TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl) | 5823 | TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) |
| 5819 | 5824 | ||
| 5820 | ErrorValueDecl = "error" Symbol ";" | 5825 | ErrorValueDecl = "error" Symbol ";" |
| 5821 | 5826 | ||
| 5822 | GlobalVarDecl = VariableDeclaration ";" | 5827 | GlobalVarDecl = option("export") VariableDeclaration ";" |
| 5828 | |||
| 5829 | LocalVarDecl = option("comptime") VariableDeclaration | ||
| 5823 | 5830 | ||
| 5824 | VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression | 5831 | VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression |
| 5825 | 5832 | ||
| 5826 | ContainerMember = (ContainerField | FnDef | GlobalVarDecl) | 5833 | ContainerMember = (ContainerField | FnDef | GlobalVarDecl) |
| 5827 | 5834 | ||
| ... | @@ -5831,21 +5838,17 @@ UseDecl = "use" Expression ";" | ... | @@ -5831,21 +5838,17 @@ UseDecl = "use" Expression ";" |
| 5831 | 5838 | ||
| 5832 | ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" | 5839 | ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" |
| 5833 | 5840 | ||
| 5834 | FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("-&gt;" TypeExpr) | 5841 | FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("-&gt;" TypeExpr) |
| 5835 | 5842 | ||
| 5836 | VisibleMod = "pub" | "export" | 5843 | FnDef = option("inline" | "export") FnProto Block |
| 5837 | |||
| 5838 | FnDef = option("inline" | "extern") FnProto Block | ||
| 5839 | 5844 | ||
| 5840 | ParamDeclList = "(" list(ParamDecl, ",") ")" | 5845 | ParamDeclList = "(" list(ParamDecl, ",") ")" |
| 5841 | 5846 | ||
| 5842 | ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...") | 5847 | ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...") |
| 5843 | 5848 | ||
| 5844 | Block = "{" many(Statement) option(Expression) "}" | 5849 | Block = option(Symbol ":") "{" many(Statement) "}" |
| 5845 | |||
| 5846 | Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ||
| 5847 | 5850 | ||
| 5848 | Label = Symbol ":" | 5851 | Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" |
| 5849 | 5852 | ||
| 5850 | TypeExpr = PrefixOpExpression | "var" | 5853 | TypeExpr = PrefixOpExpression | "var" |
| 5851 | 5854 | ||
| ... | @@ -5885,13 +5888,13 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=&gt;" option("|" option("*") Sy | ... | @@ -5885,13 +5888,13 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=&gt;" option("|" option("*") Sy |
| 5885 | 5888 | ||
| 5886 | SwitchItem = Expression | (Expression "..." Expression) | 5889 | SwitchItem = Expression | (Expression "..." Expression) |
| 5887 | 5890 | ||
| 5888 | ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body)) | 5891 | ForExpression(body) = option(Symbol ":") option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body)) |
| 5889 | 5892 | ||
| 5890 | BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression | 5893 | BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression |
| 5891 | 5894 | ||
| 5892 | ReturnExpression = option("%") "return" option(Expression) | 5895 | ReturnExpression = option("%") "return" option(Expression) |
| 5893 | 5896 | ||
| 5894 | BreakExpression = "break" option(Expression) | 5897 | BreakExpression = "break" option(":" Symbol) option(Expression) |
| 5895 | 5898 | ||
| 5896 | Defer(body) = option("%") "defer" body | 5899 | Defer(body) = option("%") "defer" body |
| 5897 | 5900 | ||
| ... | @@ -5901,7 +5904,7 @@ TryExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") | ... | @@ -5901,7 +5904,7 @@ TryExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") |
| 5901 | 5904 | ||
| 5902 | TestExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body option("else" BlockExpression(body)) | 5905 | TestExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body option("else" BlockExpression(body)) |
| 5903 | 5906 | ||
| 5904 | WhileExpression(body) = option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body)) | 5907 | WhileExpression(body) = option(Symbol ":") option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body)) |
| 5905 | 5908 | ||
| 5906 | BoolAndExpression = ComparisonExpression "and" BoolAndExpression | ComparisonExpression | 5909 | BoolAndExpression = ComparisonExpression "and" BoolAndExpression | ComparisonExpression |
| 5907 | 5910 | ||
| ... | @@ -5949,15 +5952,13 @@ StructLiteralField = "." Symbol "=" Expression | ... | @@ -5949,15 +5952,13 @@ StructLiteralField = "." Symbol "=" Expression |
| 5949 | 5952 | ||
| 5950 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" | 5953 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" |
| 5951 | 5954 | ||
| 5952 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | 5955 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol)) |
| 5953 | 5956 | ||
| 5954 | ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr | 5957 | ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr |
| 5955 | 5958 | ||
| 5956 | GotoExpression = "goto" Symbol | ||
| 5957 | |||
| 5958 | GroupedExpression = "(" Expression ")" | 5959 | GroupedExpression = "(" Expression ")" |
| 5959 | 5960 | ||
| 5960 | KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable" | 5961 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" |
| 5961 | 5962 | ||
| 5962 | ContainerDecl = option("extern" | "packed") | 5963 | ContainerDecl = option("extern" | "packed") |
| 5963 | ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression))) | 5964 | ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression))) |
example/shared_library/mathtest.zig+1-1| ... | @@ -1,3 +1,3 @@ | ... | @@ -1,3 +1,3 @@ |
| 1 | export fn add(a: i32, b: i32) -> i32 { | 1 | export fn add(a: i32, b: i32) -> i32 { |
| 2 | a + b | 2 | return a + b; |
| 3 | } | 3 | } |
src-self-hosted/ast.zig created+273| ... | @@ -0,0 +1,273 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const ArrayList = std.ArrayList; | ||
| 4 | const Token = @import("tokenizer.zig").Token; | ||
| 5 | const mem = std.mem; | ||
| 6 | |||
| 7 | pub const Node = struct { | ||
| 8 | id: Id, | ||
| 9 | |||
| 10 | pub const Id = enum { | ||
| 11 | Root, | ||
| 12 | VarDecl, | ||
| 13 | Identifier, | ||
| 14 | FnProto, | ||
| 15 | ParamDecl, | ||
| 16 | Block, | ||
| 17 | InfixOp, | ||
| 18 | PrefixOp, | ||
| 19 | IntegerLiteral, | ||
| 20 | FloatLiteral, | ||
| 21 | }; | ||
| 22 | |||
| 23 | pub fn iterate(base: &Node, index: usize) -> ?&Node { | ||
| 24 | return switch (base.id) { | ||
| 25 | Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index), | ||
| 26 | Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index), | ||
| 27 | Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).iterate(index), | ||
| 28 | Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index), | ||
| 29 | Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index), | ||
| 30 | Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index), | ||
| 31 | Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index), | ||
| 32 | Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index), | ||
| 33 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index), | ||
| 34 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index), | ||
| 35 | }; | ||
| 36 | } | ||
| 37 | |||
| 38 | pub fn destroy(base: &Node, allocator: &mem.Allocator) { | ||
| 39 | return switch (base.id) { | ||
| 40 | Id.Root => allocator.destroy(@fieldParentPtr(NodeRoot, "base", base)), | ||
| 41 | Id.VarDecl => allocator.destroy(@fieldParentPtr(NodeVarDecl, "base", base)), | ||
| 42 | Id.Identifier => allocator.destroy(@fieldParentPtr(NodeIdentifier, "base", base)), | ||
| 43 | Id.FnProto => allocator.destroy(@fieldParentPtr(NodeFnProto, "base", base)), | ||
| 44 | Id.ParamDecl => allocator.destroy(@fieldParentPtr(NodeParamDecl, "base", base)), | ||
| 45 | Id.Block => allocator.destroy(@fieldParentPtr(NodeBlock, "base", base)), | ||
| 46 | Id.InfixOp => allocator.destroy(@fieldParentPtr(NodeInfixOp, "base", base)), | ||
| 47 | Id.PrefixOp => allocator.destroy(@fieldParentPtr(NodePrefixOp, "base", base)), | ||
| 48 | Id.IntegerLiteral => allocator.destroy(@fieldParentPtr(NodeIntegerLiteral, "base", base)), | ||
| 49 | Id.FloatLiteral => allocator.destroy(@fieldParentPtr(NodeFloatLiteral, "base", base)), | ||
| 50 | }; | ||
| 51 | } | ||
| 52 | }; | ||
| 53 | |||
| 54 | pub const NodeRoot = struct { | ||
| 55 | base: Node, | ||
| 56 | decls: ArrayList(&Node), | ||
| 57 | |||
| 58 | pub fn iterate(self: &NodeRoot, index: usize) -> ?&Node { | ||
| 59 | if (index < self.decls.len) { | ||
| 60 | return self.decls.items[self.decls.len - index - 1]; | ||
| 61 | } | ||
| 62 | return null; | ||
| 63 | } | ||
| 64 | }; | ||
| 65 | |||
| 66 | pub const NodeVarDecl = struct { | ||
| 67 | base: Node, | ||
| 68 | visib_token: ?Token, | ||
| 69 | name_token: Token, | ||
| 70 | eq_token: Token, | ||
| 71 | mut_token: Token, | ||
| 72 | comptime_token: ?Token, | ||
| 73 | extern_token: ?Token, | ||
| 74 | lib_name: ?&Node, | ||
| 75 | type_node: ?&Node, | ||
| 76 | align_node: ?&Node, | ||
| 77 | init_node: ?&Node, | ||
| 78 | |||
| 79 | pub fn iterate(self: &NodeVarDecl, index: usize) -> ?&Node { | ||
| 80 | var i = index; | ||
| 81 | |||
| 82 | if (self.type_node) |type_node| { | ||
| 83 | if (i < 1) return type_node; | ||
| 84 | i -= 1; | ||
| 85 | } | ||
| 86 | |||
| 87 | if (self.align_node) |align_node| { | ||
| 88 | if (i < 1) return align_node; | ||
| 89 | i -= 1; | ||
| 90 | } | ||
| 91 | |||
| 92 | if (self.init_node) |init_node| { | ||
| 93 | if (i < 1) return init_node; | ||
| 94 | i -= 1; | ||
| 95 | } | ||
| 96 | |||
| 97 | return null; | ||
| 98 | } | ||
| 99 | }; | ||
| 100 | |||
| 101 | pub const NodeIdentifier = struct { | ||
| 102 | base: Node, | ||
| 103 | name_token: Token, | ||
| 104 | |||
| 105 | pub fn iterate(self: &NodeIdentifier, index: usize) -> ?&Node { | ||
| 106 | return null; | ||
| 107 | } | ||
| 108 | }; | ||
| 109 | |||
| 110 | pub const NodeFnProto = struct { | ||
| 111 | base: Node, | ||
| 112 | visib_token: ?Token, | ||
| 113 | fn_token: Token, | ||
| 114 | name_token: ?Token, | ||
| 115 | params: ArrayList(&Node), | ||
| 116 | return_type: ?&Node, | ||
| 117 | var_args_token: ?Token, | ||
| 118 | extern_token: ?Token, | ||
| 119 | inline_token: ?Token, | ||
| 120 | cc_token: ?Token, | ||
| 121 | body_node: ?&Node, | ||
| 122 | lib_name: ?&Node, // populated if this is an extern declaration | ||
| 123 | align_expr: ?&Node, // populated if align(A) is present | ||
| 124 | |||
| 125 | pub fn iterate(self: &NodeFnProto, index: usize) -> ?&Node { | ||
| 126 | var i = index; | ||
| 127 | |||
| 128 | if (self.body_node) |body_node| { | ||
| 129 | if (i < 1) return body_node; | ||
| 130 | i -= 1; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (self.return_type) |return_type| { | ||
| 134 | if (i < 1) return return_type; | ||
| 135 | i -= 1; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (self.align_expr) |align_expr| { | ||
| 139 | if (i < 1) return align_expr; | ||
| 140 | i -= 1; | ||
| 141 | } | ||
| 142 | |||
| 143 | if (i < self.params.len) return self.params.items[self.params.len - i - 1]; | ||
| 144 | i -= self.params.len; | ||
| 145 | |||
| 146 | if (self.lib_name) |lib_name| { | ||
| 147 | if (i < 1) return lib_name; | ||
| 148 | i -= 1; | ||
| 149 | } | ||
| 150 | |||
| 151 | return null; | ||
| 152 | } | ||
| 153 | }; | ||
| 154 | |||
| 155 | pub const NodeParamDecl = struct { | ||
| 156 | base: Node, | ||
| 157 | comptime_token: ?Token, | ||
| 158 | noalias_token: ?Token, | ||
| 159 | name_token: ?Token, | ||
| 160 | type_node: &Node, | ||
| 161 | var_args_token: ?Token, | ||
| 162 | |||
| 163 | pub fn iterate(self: &NodeParamDecl, index: usize) -> ?&Node { | ||
| 164 | var i = index; | ||
| 165 | |||
| 166 | if (i < 1) return self.type_node; | ||
| 167 | i -= 1; | ||
| 168 | |||
| 169 | return null; | ||
| 170 | } | ||
| 171 | }; | ||
| 172 | |||
| 173 | pub const NodeBlock = struct { | ||
| 174 | base: Node, | ||
| 175 | begin_token: Token, | ||
| 176 | end_token: Token, | ||
| 177 | statements: ArrayList(&Node), | ||
| 178 | |||
| 179 | pub fn iterate(self: &NodeBlock, index: usize) -> ?&Node { | ||
| 180 | var i = index; | ||
| 181 | |||
| 182 | if (i < self.statements.len) return self.statements.items[i]; | ||
| 183 | i -= self.statements.len; | ||
| 184 | |||
| 185 | return null; | ||
| 186 | } | ||
| 187 | }; | ||
| 188 | |||
| 189 | pub const NodeInfixOp = struct { | ||
| 190 | base: Node, | ||
| 191 | op_token: Token, | ||
| 192 | lhs: &Node, | ||
| 193 | op: InfixOp, | ||
| 194 | rhs: &Node, | ||
| 195 | |||
| 196 | const InfixOp = enum { | ||
| 197 | EqualEqual, | ||
| 198 | BangEqual, | ||
| 199 | }; | ||
| 200 | |||
| 201 | pub fn iterate(self: &NodeInfixOp, index: usize) -> ?&Node { | ||
| 202 | var i = index; | ||
| 203 | |||
| 204 | if (i < 1) return self.lhs; | ||
| 205 | i -= 1; | ||
| 206 | |||
| 207 | switch (self.op) { | ||
| 208 | InfixOp.EqualEqual => {}, | ||
| 209 | InfixOp.BangEqual => {}, | ||
| 210 | } | ||
| 211 | |||
| 212 | if (i < 1) return self.rhs; | ||
| 213 | i -= 1; | ||
| 214 | |||
| 215 | return null; | ||
| 216 | } | ||
| 217 | }; | ||
| 218 | |||
| 219 | pub const NodePrefixOp = struct { | ||
| 220 | base: Node, | ||
| 221 | op_token: Token, | ||
| 222 | op: PrefixOp, | ||
| 223 | rhs: &Node, | ||
| 224 | |||
| 225 | const PrefixOp = union(enum) { | ||
| 226 | Return, | ||
| 227 | AddrOf: AddrOfInfo, | ||
| 228 | }; | ||
| 229 | const AddrOfInfo = struct { | ||
| 230 | align_expr: ?&Node, | ||
| 231 | bit_offset_start_token: ?Token, | ||
| 232 | bit_offset_end_token: ?Token, | ||
| 233 | const_token: ?Token, | ||
| 234 | volatile_token: ?Token, | ||
| 235 | }; | ||
| 236 | |||
| 237 | pub fn iterate(self: &NodePrefixOp, index: usize) -> ?&Node { | ||
| 238 | var i = index; | ||
| 239 | |||
| 240 | switch (self.op) { | ||
| 241 | PrefixOp.Return => {}, | ||
| 242 | PrefixOp.AddrOf => |addr_of_info| { | ||
| 243 | if (addr_of_info.align_expr) |align_expr| { | ||
| 244 | if (i < 1) return align_expr; | ||
| 245 | i -= 1; | ||
| 246 | } | ||
| 247 | }, | ||
| 248 | } | ||
| 249 | |||
| 250 | if (i < 1) return self.rhs; | ||
| 251 | i -= 1; | ||
| 252 | |||
| 253 | return null; | ||
| 254 | } | ||
| 255 | }; | ||
| 256 | |||
| 257 | pub const NodeIntegerLiteral = struct { | ||
| 258 | base: Node, | ||
| 259 | token: Token, | ||
| 260 | |||
| 261 | pub fn iterate(self: &NodeIntegerLiteral, index: usize) -> ?&Node { | ||
| 262 | return null; | ||
| 263 | } | ||
| 264 | }; | ||
| 265 | |||
| 266 | pub const NodeFloatLiteral = struct { | ||
| 267 | base: Node, | ||
| 268 | token: Token, | ||
| 269 | |||
| 270 | pub fn iterate(self: &NodeFloatLiteral, index: usize) -> ?&Node { | ||
| 271 | return null; | ||
| 272 | } | ||
| 273 | }; | ||
src-self-hosted/c.zig created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | pub use @cImport({ | ||
| 2 | @cInclude("llvm-c/Core.h"); | ||
| 3 | @cInclude("llvm-c/Analysis.h"); | ||
| 4 | @cInclude("llvm-c/Target.h"); | ||
| 5 | @cInclude("llvm-c/Initialization.h"); | ||
| 6 | @cInclude("llvm-c/TargetMachine.h"); | ||
| 7 | }); | ||
src-self-hosted/llvm.zig created+13| ... | @@ -0,0 +1,13 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const c = @import("c.zig"); | ||
| 3 | const assert = @import("std").debug.assert; | ||
| 4 | |||
| 5 | pub const ValueRef = removeNullability(c.LLVMValueRef); | ||
| 6 | pub const ModuleRef = removeNullability(c.LLVMModuleRef); | ||
| 7 | pub const ContextRef = removeNullability(c.LLVMContextRef); | ||
| 8 | pub const BuilderRef = removeNullability(c.LLVMBuilderRef); | ||
| 9 | |||
| 10 | fn removeNullability(comptime T: type) -> type { | ||
| 11 | comptime assert(@typeId(T) == builtin.TypeId.Nullable); | ||
| 12 | return T.Child; | ||
| 13 | } | ||
src-self-hosted/main.zig+517-181| ... | @@ -1,208 +1,476 @@ | ... | @@ -1,208 +1,476 @@ |
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const io = std.io; | ||
| 4 | const os = std.os; | ||
| 5 | const heap = std.heap; | ||
| 6 | const warn = std.debug.warn; | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | const target = @import("target.zig"); | ||
| 9 | const Target = target.Target; | ||
| 10 | const Module = @import("module.zig").Module; | ||
| 11 | const ErrColor = Module.ErrColor; | ||
| 12 | const Emit = Module.Emit; | ||
| 1 | const builtin = @import("builtin"); | 13 | const builtin = @import("builtin"); |
| 2 | const io = @import("std").io; | 14 | const ArrayList = std.ArrayList; |
| 3 | const os = @import("std").os; | ||
| 4 | const heap = @import("std").heap; | ||
| 5 | 15 | ||
| 6 | // TODO: sync up CLI with c++ code | 16 | error InvalidCommandLineArguments; |
| 7 | // TODO: concurrency | 17 | error ZigLibDirNotFound; |
| 18 | error ZigInstallationNotFound; | ||
| 8 | 19 | ||
| 9 | error InvalidArgument; | 20 | const default_zig_cache_name = "zig-cache"; |
| 10 | error MissingArg0; | ||
| 11 | |||
| 12 | var arg0: []u8 = undefined; | ||
| 13 | |||
| 14 | var stderr_file: io.File = undefined; | ||
| 15 | const stderr = &stderr_file.out_stream; | ||
| 16 | 21 | ||
| 17 | pub fn main() -> %void { | 22 | pub fn main() -> %void { |
| 18 | stderr_file = %return io.getStdErr(); | 23 | main2() %% |err| { |
| 19 | if (internal_main()) |_| { | 24 | if (err != error.InvalidCommandLineArguments) { |
| 20 | return; | 25 | warn("{}\n", @errorName(err)); |
| 21 | } else |err| { | ||
| 22 | if (err == error.InvalidArgument) { | ||
| 23 | stderr.print("\n") %% return err; | ||
| 24 | printUsage(stderr) %% return err; | ||
| 25 | } else { | ||
| 26 | stderr.print("{}\n", err) %% return err; | ||
| 27 | } | 26 | } |
| 28 | return err; | 27 | return err; |
| 29 | } | 28 | }; |
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | pub fn internal_main() -> %void { | 31 | const Cmd = enum { |
| 33 | var args_it = os.args(); | 32 | None, |
| 33 | Build, | ||
| 34 | Test, | ||
| 35 | Version, | ||
| 36 | Zen, | ||
| 37 | TranslateC, | ||
| 38 | Targets, | ||
| 39 | }; | ||
| 34 | 40 | ||
| 35 | var incrementing_allocator = heap.IncrementingAllocator.init(10 * 1024 * 1024) %% |err| { | 41 | fn badArgs(comptime format: []const u8, args: ...) -> error { |
| 36 | io.stderr.printf("Unable to allocate memory") %% {}; | 42 | var stderr = %return io.getStdErr(); |
| 37 | return err; | 43 | var stderr_stream_adapter = io.FileOutStream.init(&stderr); |
| 38 | }; | 44 | const stderr_stream = &stderr_stream_adapter.stream; |
| 39 | defer incrementing_allocator.deinit(); | 45 | %return stderr_stream.print(format ++ "\n\n", args); |
| 46 | %return printUsage(&stderr_stream_adapter.stream); | ||
| 47 | return error.InvalidCommandLineArguments; | ||
| 48 | } | ||
| 49 | |||
| 50 | pub fn main2() -> %void { | ||
| 51 | const allocator = std.heap.c_allocator; | ||
| 52 | |||
| 53 | const args = %return os.argsAlloc(allocator); | ||
| 54 | defer os.argsFree(allocator, args); | ||
| 40 | 55 | ||
| 41 | const allocator = &incrementing_allocator.allocator; | 56 | var cmd = Cmd.None; |
| 42 | 57 | var build_kind: Module.Kind = undefined; | |
| 43 | arg0 = %return (args_it.next(allocator) ?? error.MissingArg0); | 58 | var build_mode: builtin.Mode = builtin.Mode.Debug; |
| 44 | defer allocator.free(arg0); | 59 | var color = ErrColor.Auto; |
| 60 | var emit_file_type = Emit.Binary; | ||
| 45 | 61 | ||
| 46 | var build_mode = builtin.Mode.Debug; | ||
| 47 | var strip = false; | 62 | var strip = false; |
| 48 | var is_static = false; | 63 | var is_static = false; |
| 49 | var verbose = false; | 64 | var verbose_tokenize = false; |
| 65 | var verbose_ast_tree = false; | ||
| 66 | var verbose_ast_fmt = false; | ||
| 50 | var verbose_link = false; | 67 | var verbose_link = false; |
| 51 | var verbose_ir = false; | 68 | var verbose_ir = false; |
| 69 | var verbose_llvm_ir = false; | ||
| 70 | var verbose_cimport = false; | ||
| 52 | var mwindows = false; | 71 | var mwindows = false; |
| 53 | var mconsole = false; | 72 | var mconsole = false; |
| 73 | var rdynamic = false; | ||
| 74 | var each_lib_rpath = false; | ||
| 75 | var timing_info = false; | ||
| 76 | |||
| 77 | var in_file_arg: ?[]u8 = null; | ||
| 78 | var out_file: ?[]u8 = null; | ||
| 79 | var out_file_h: ?[]u8 = null; | ||
| 80 | var out_name_arg: ?[]u8 = null; | ||
| 81 | var libc_lib_dir_arg: ?[]u8 = null; | ||
| 82 | var libc_static_lib_dir_arg: ?[]u8 = null; | ||
| 83 | var libc_include_dir_arg: ?[]u8 = null; | ||
| 84 | var msvc_lib_dir_arg: ?[]u8 = null; | ||
| 85 | var kernel32_lib_dir_arg: ?[]u8 = null; | ||
| 86 | var zig_install_prefix: ?[]u8 = null; | ||
| 87 | var dynamic_linker_arg: ?[]u8 = null; | ||
| 88 | var cache_dir_arg: ?[]const u8 = null; | ||
| 89 | var target_arch: ?[]u8 = null; | ||
| 90 | var target_os: ?[]u8 = null; | ||
| 91 | var target_environ: ?[]u8 = null; | ||
| 92 | var mmacosx_version_min: ?[]u8 = null; | ||
| 93 | var mios_version_min: ?[]u8 = null; | ||
| 94 | var linker_script_arg: ?[]u8 = null; | ||
| 95 | var test_name_prefix_arg: ?[]u8 = null; | ||
| 96 | |||
| 97 | var test_filters = ArrayList([]const u8).init(allocator); | ||
| 98 | defer test_filters.deinit(); | ||
| 99 | |||
| 100 | var lib_dirs = ArrayList([]const u8).init(allocator); | ||
| 101 | defer lib_dirs.deinit(); | ||
| 54 | 102 | ||
| 55 | while (args_it.next()) |arg_or_err| { | 103 | var clang_argv = ArrayList([]const u8).init(allocator); |
| 56 | const arg = %return arg_or_err; | 104 | defer clang_argv.deinit(); |
| 57 | 105 | ||
| 58 | if (arg[0] == '-') { | 106 | var llvm_argv = ArrayList([]const u8).init(allocator); |
| 59 | if (strcmp(arg, "--release-fast") == 0) { | 107 | defer llvm_argv.deinit(); |
| 108 | |||
| 109 | var link_libs = ArrayList([]const u8).init(allocator); | ||
| 110 | defer link_libs.deinit(); | ||
| 111 | |||
| 112 | var frameworks = ArrayList([]const u8).init(allocator); | ||
| 113 | defer frameworks.deinit(); | ||
| 114 | |||
| 115 | var objects = ArrayList([]const u8).init(allocator); | ||
| 116 | defer objects.deinit(); | ||
| 117 | |||
| 118 | var asm_files = ArrayList([]const u8).init(allocator); | ||
| 119 | defer asm_files.deinit(); | ||
| 120 | |||
| 121 | var rpath_list = ArrayList([]const u8).init(allocator); | ||
| 122 | defer rpath_list.deinit(); | ||
| 123 | |||
| 124 | var ver_major: u32 = 0; | ||
| 125 | var ver_minor: u32 = 0; | ||
| 126 | var ver_patch: u32 = 0; | ||
| 127 | |||
| 128 | var arg_i: usize = 1; | ||
| 129 | while (arg_i < args.len) : (arg_i += 1) { | ||
| 130 | const arg = args[arg_i]; | ||
| 131 | |||
| 132 | if (arg.len != 0 and arg[0] == '-') { | ||
| 133 | if (mem.eql(u8, arg, "--release-fast")) { | ||
| 60 | build_mode = builtin.Mode.ReleaseFast; | 134 | build_mode = builtin.Mode.ReleaseFast; |
| 61 | } else if (strcmp(arg, "--release-safe") == 0) { | 135 | } else if (mem.eql(u8, arg, "--release-safe")) { |
| 62 | build_mode = builtin.Mode.ReleaseSafe; | 136 | build_mode = builtin.Mode.ReleaseSafe; |
| 63 | } else if (strcmp(arg, "--strip") == 0) { | 137 | } else if (mem.eql(u8, arg, "--strip")) { |
| 64 | strip = true; | 138 | strip = true; |
| 65 | } else if (strcmp(arg, "--static") == 0) { | 139 | } else if (mem.eql(u8, arg, "--static")) { |
| 66 | is_static = true; | 140 | is_static = true; |
| 67 | } else if (strcmp(arg, "--verbose") == 0) { | 141 | } else if (mem.eql(u8, arg, "--verbose-tokenize")) { |
| 68 | verbose = true; | 142 | verbose_tokenize = true; |
| 69 | } else if (strcmp(arg, "--verbose-link") == 0) { | 143 | } else if (mem.eql(u8, arg, "--verbose-ast-tree")) { |
| 144 | verbose_ast_tree = true; | ||
| 145 | } else if (mem.eql(u8, arg, "--verbose-ast-fmt")) { | ||
| 146 | verbose_ast_fmt = true; | ||
| 147 | } else if (mem.eql(u8, arg, "--verbose-link")) { | ||
| 70 | verbose_link = true; | 148 | verbose_link = true; |
| 71 | } else if (strcmp(arg, "--verbose-ir") == 0) { | 149 | } else if (mem.eql(u8, arg, "--verbose-ir")) { |
| 72 | verbose_ir = true; | 150 | verbose_ir = true; |
| 73 | } else if (strcmp(arg, "-mwindows") == 0) { | 151 | } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { |
| 152 | verbose_llvm_ir = true; | ||
| 153 | } else if (mem.eql(u8, arg, "--verbose-cimport")) { | ||
| 154 | verbose_cimport = true; | ||
| 155 | } else if (mem.eql(u8, arg, "-mwindows")) { | ||
| 74 | mwindows = true; | 156 | mwindows = true; |
| 75 | } else if (strcmp(arg, "-mconsole") == 0) { | 157 | } else if (mem.eql(u8, arg, "-mconsole")) { |
| 76 | mconsole = true; | 158 | mconsole = true; |
| 77 | } else if (strcmp(arg, "-municode") == 0) { | 159 | } else if (mem.eql(u8, arg, "-rdynamic")) { |
| 78 | municode = true; | ||
| 79 | } else if (strcmp(arg, "-rdynamic") == 0) { | ||
| 80 | rdynamic = true; | 160 | rdynamic = true; |
| 81 | } else if (strcmp(arg, "--each-lib-rpath") == 0) { | 161 | } else if (mem.eql(u8, arg, "--each-lib-rpath")) { |
| 82 | each_lib_rpath = true; | 162 | each_lib_rpath = true; |
| 83 | } else if (strcmp(arg, "--enable-timing-info") == 0) { | 163 | } else if (mem.eql(u8, arg, "--enable-timing-info")) { |
| 84 | timing_info = true; | 164 | timing_info = true; |
| 85 | } else if (strcmp(arg, "--test-cmd-bin") == 0) { | 165 | } else if (mem.eql(u8, arg, "--test-cmd-bin")) { |
| 86 | test_exec_args.append(nullptr); | 166 | @panic("TODO --test-cmd-bin"); |
| 87 | } else if (arg[1] == 'L' && arg[2] != 0) { | 167 | } else if (arg[1] == 'L' and arg.len > 2) { |
| 88 | // alias for --library-path | 168 | // alias for --library-path |
| 89 | lib_dirs.append(&arg[2]); | 169 | %return lib_dirs.append(arg[1..]); |
| 90 | } else if (strcmp(arg, "--pkg-begin") == 0) { | 170 | } else if (mem.eql(u8, arg, "--pkg-begin")) { |
| 91 | if (i + 2 >= argc) { | 171 | @panic("TODO --pkg-begin"); |
| 92 | fprintf(stderr, "Expected 2 arguments after --pkg-begin\n"); | 172 | } else if (mem.eql(u8, arg, "--pkg-end")) { |
| 93 | return usage(arg0); | 173 | @panic("TODO --pkg-end"); |
| 94 | } | 174 | } else if (arg_i + 1 >= args.len) { |
| 95 | CliPkg *new_cur_pkg = allocate<CliPkg>(1); | 175 | return badArgs("expected another argument after {}", arg); |
| 96 | i += 1; | ||
| 97 | new_cur_pkg->name = argv[i]; | ||
| 98 | i += 1; | ||
| 99 | new_cur_pkg->path = argv[i]; | ||
| 100 | new_cur_pkg->parent = cur_pkg; | ||
| 101 | cur_pkg->children.append(new_cur_pkg); | ||
| 102 | cur_pkg = new_cur_pkg; | ||
| 103 | } else if (strcmp(arg, "--pkg-end") == 0) { | ||
| 104 | if (cur_pkg->parent == nullptr) { | ||
| 105 | fprintf(stderr, "Encountered --pkg-end with no matching --pkg-begin\n"); | ||
| 106 | return EXIT_FAILURE; | ||
| 107 | } | ||
| 108 | cur_pkg = cur_pkg->parent; | ||
| 109 | } else if (i + 1 >= argc) { | ||
| 110 | fprintf(stderr, "Expected another argument after %s\n", arg); | ||
| 111 | return usage(arg0); | ||
| 112 | } else { | 176 | } else { |
| 113 | i += 1; | 177 | arg_i += 1; |
| 114 | if (strcmp(arg, "--output") == 0) { | 178 | if (mem.eql(u8, arg, "--output")) { |
| 115 | out_file = argv[i]; | 179 | out_file = args[arg_i]; |
| 116 | } else if (strcmp(arg, "--output-h") == 0) { | 180 | } else if (mem.eql(u8, arg, "--output-h")) { |
| 117 | out_file_h = argv[i]; | 181 | out_file_h = args[arg_i]; |
| 118 | } else if (strcmp(arg, "--color") == 0) { | 182 | } else if (mem.eql(u8, arg, "--color")) { |
| 119 | if (strcmp(argv[i], "auto") == 0) { | 183 | if (mem.eql(u8, args[arg_i], "auto")) { |
| 120 | color = ErrColorAuto; | 184 | color = ErrColor.Auto; |
| 121 | } else if (strcmp(argv[i], "on") == 0) { | 185 | } else if (mem.eql(u8, args[arg_i], "on")) { |
| 122 | color = ErrColorOn; | 186 | color = ErrColor.On; |
| 123 | } else if (strcmp(argv[i], "off") == 0) { | 187 | } else if (mem.eql(u8, args[arg_i], "off")) { |
| 124 | color = ErrColorOff; | 188 | color = ErrColor.Off; |
| 125 | } else { | 189 | } else { |
| 126 | fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n"); | 190 | return badArgs("--color options are 'auto', 'on', or 'off'"); |
| 127 | return usage(arg0); | ||
| 128 | } | 191 | } |
| 129 | } else if (strcmp(arg, "--name") == 0) { | 192 | } else if (mem.eql(u8, arg, "--emit")) { |
| 130 | out_name = argv[i]; | 193 | if (mem.eql(u8, args[arg_i], "asm")) { |
| 131 | } else if (strcmp(arg, "--libc-lib-dir") == 0) { | 194 | emit_file_type = Emit.Assembly; |
| 132 | libc_lib_dir = argv[i]; | 195 | } else if (mem.eql(u8, args[arg_i], "bin")) { |
| 133 | } else if (strcmp(arg, "--libc-static-lib-dir") == 0) { | 196 | emit_file_type = Emit.Binary; |
| 134 | libc_static_lib_dir = argv[i]; | 197 | } else if (mem.eql(u8, args[arg_i], "llvm-ir")) { |
| 135 | } else if (strcmp(arg, "--libc-include-dir") == 0) { | 198 | emit_file_type = Emit.LlvmIr; |
| 136 | libc_include_dir = argv[i]; | 199 | } else { |
| 137 | } else if (strcmp(arg, "--msvc-lib-dir") == 0) { | 200 | return badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'"); |
| 138 | msvc_lib_dir = argv[i]; | 201 | } |
| 139 | } else if (strcmp(arg, "--kernel32-lib-dir") == 0) { | 202 | } else if (mem.eql(u8, arg, "--name")) { |
| 140 | kernel32_lib_dir = argv[i]; | 203 | out_name_arg = args[arg_i]; |
| 141 | } else if (strcmp(arg, "--zig-install-prefix") == 0) { | 204 | } else if (mem.eql(u8, arg, "--libc-lib-dir")) { |
| 142 | zig_install_prefix = argv[i]; | 205 | libc_lib_dir_arg = args[arg_i]; |
| 143 | } else if (strcmp(arg, "--dynamic-linker") == 0) { | 206 | } else if (mem.eql(u8, arg, "--libc-static-lib-dir")) { |
| 144 | dynamic_linker = argv[i]; | 207 | libc_static_lib_dir_arg = args[arg_i]; |
| 145 | } else if (strcmp(arg, "-isystem") == 0) { | 208 | } else if (mem.eql(u8, arg, "--libc-include-dir")) { |
| 146 | clang_argv.append("-isystem"); | 209 | libc_include_dir_arg = args[arg_i]; |
| 147 | clang_argv.append(argv[i]); | 210 | } else if (mem.eql(u8, arg, "--msvc-lib-dir")) { |
| 148 | } else if (strcmp(arg, "-dirafter") == 0) { | 211 | msvc_lib_dir_arg = args[arg_i]; |
| 149 | clang_argv.append("-dirafter"); | 212 | } else if (mem.eql(u8, arg, "--kernel32-lib-dir")) { |
| 150 | clang_argv.append(argv[i]); | 213 | kernel32_lib_dir_arg = args[arg_i]; |
| 151 | } else if (strcmp(arg, "-mllvm") == 0) { | 214 | } else if (mem.eql(u8, arg, "--zig-install-prefix")) { |
| 152 | clang_argv.append("-mllvm"); | 215 | zig_install_prefix = args[arg_i]; |
| 153 | clang_argv.append(argv[i]); | 216 | } else if (mem.eql(u8, arg, "--dynamic-linker")) { |
| 154 | 217 | dynamic_linker_arg = args[arg_i]; | |
| 155 | llvm_argv.append(argv[i]); | 218 | } else if (mem.eql(u8, arg, "-isystem")) { |
| 156 | } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) { | 219 | %return clang_argv.append("-isystem"); |
| 157 | lib_dirs.append(argv[i]); | 220 | %return clang_argv.append(args[arg_i]); |
| 158 | } else if (strcmp(arg, "--library") == 0) { | 221 | } else if (mem.eql(u8, arg, "-dirafter")) { |
| 159 | link_libs.append(argv[i]); | 222 | %return clang_argv.append("-dirafter"); |
| 160 | } else if (strcmp(arg, "--object") == 0) { | 223 | %return clang_argv.append(args[arg_i]); |
| 161 | objects.append(argv[i]); | 224 | } else if (mem.eql(u8, arg, "-mllvm")) { |
| 162 | } else if (strcmp(arg, "--assembly") == 0) { | 225 | %return clang_argv.append("-mllvm"); |
| 163 | asm_files.append(argv[i]); | 226 | %return clang_argv.append(args[arg_i]); |
| 164 | } else if (strcmp(arg, "--cache-dir") == 0) { | 227 | |
| 165 | cache_dir = argv[i]; | 228 | %return llvm_argv.append(args[arg_i]); |
| 166 | } else if (strcmp(arg, "--target-arch") == 0) { | 229 | } else if (mem.eql(u8, arg, "--library-path") or mem.eql(u8, arg, "-L")) { |
| 167 | target_arch = argv[i]; | 230 | %return lib_dirs.append(args[arg_i]); |
| 168 | } else if (strcmp(arg, "--target-os") == 0) { | 231 | } else if (mem.eql(u8, arg, "--library")) { |
| 169 | target_os = argv[i]; | 232 | %return link_libs.append(args[arg_i]); |
| 170 | } else if (strcmp(arg, "--target-environ") == 0) { | 233 | } else if (mem.eql(u8, arg, "--object")) { |
| 171 | target_environ = argv[i]; | 234 | %return objects.append(args[arg_i]); |
| 172 | } else if (strcmp(arg, "-mmacosx-version-min") == 0) { | 235 | } else if (mem.eql(u8, arg, "--assembly")) { |
| 173 | mmacosx_version_min = argv[i]; | 236 | %return asm_files.append(args[arg_i]); |
| 174 | } else if (strcmp(arg, "-mios-version-min") == 0) { | 237 | } else if (mem.eql(u8, arg, "--cache-dir")) { |
| 175 | mios_version_min = argv[i]; | 238 | cache_dir_arg = args[arg_i]; |
| 176 | } else if (strcmp(arg, "-framework") == 0) { | 239 | } else if (mem.eql(u8, arg, "--target-arch")) { |
| 177 | frameworks.append(argv[i]); | 240 | target_arch = args[arg_i]; |
| 178 | } else if (strcmp(arg, "--linker-script") == 0) { | 241 | } else if (mem.eql(u8, arg, "--target-os")) { |
| 179 | linker_script = argv[i]; | 242 | target_os = args[arg_i]; |
| 180 | } else if (strcmp(arg, "-rpath") == 0) { | 243 | } else if (mem.eql(u8, arg, "--target-environ")) { |
| 181 | rpath_list.append(argv[i]); | 244 | target_environ = args[arg_i]; |
| 182 | } else if (strcmp(arg, "--test-filter") == 0) { | 245 | } else if (mem.eql(u8, arg, "-mmacosx-version-min")) { |
| 183 | test_filter = argv[i]; | 246 | mmacosx_version_min = args[arg_i]; |
| 184 | } else if (strcmp(arg, "--test-name-prefix") == 0) { | 247 | } else if (mem.eql(u8, arg, "-mios-version-min")) { |
| 185 | test_name_prefix = argv[i]; | 248 | mios_version_min = args[arg_i]; |
| 186 | } else if (strcmp(arg, "--ver-major") == 0) { | 249 | } else if (mem.eql(u8, arg, "-framework")) { |
| 187 | ver_major = atoi(argv[i]); | 250 | %return frameworks.append(args[arg_i]); |
| 188 | } else if (strcmp(arg, "--ver-minor") == 0) { | 251 | } else if (mem.eql(u8, arg, "--linker-script")) { |
| 189 | ver_minor = atoi(argv[i]); | 252 | linker_script_arg = args[arg_i]; |
| 190 | } else if (strcmp(arg, "--ver-patch") == 0) { | 253 | } else if (mem.eql(u8, arg, "-rpath")) { |
| 191 | ver_patch = atoi(argv[i]); | 254 | %return rpath_list.append(args[arg_i]); |
| 192 | } else if (strcmp(arg, "--test-cmd") == 0) { | 255 | } else if (mem.eql(u8, arg, "--test-filter")) { |
| 193 | test_exec_args.append(argv[i]); | 256 | %return test_filters.append(args[arg_i]); |
| 257 | } else if (mem.eql(u8, arg, "--test-name-prefix")) { | ||
| 258 | test_name_prefix_arg = args[arg_i]; | ||
| 259 | } else if (mem.eql(u8, arg, "--ver-major")) { | ||
| 260 | ver_major = %return std.fmt.parseUnsigned(u32, args[arg_i], 10); | ||
| 261 | } else if (mem.eql(u8, arg, "--ver-minor")) { | ||
| 262 | ver_minor = %return std.fmt.parseUnsigned(u32, args[arg_i], 10); | ||
| 263 | } else if (mem.eql(u8, arg, "--ver-patch")) { | ||
| 264 | ver_patch = %return std.fmt.parseUnsigned(u32, args[arg_i], 10); | ||
| 265 | } else if (mem.eql(u8, arg, "--test-cmd")) { | ||
| 266 | @panic("TODO --test-cmd"); | ||
| 194 | } else { | 267 | } else { |
| 195 | fprintf(stderr, "Invalid argument: %s\n", arg); | 268 | return badArgs("invalid argument: {}", arg); |
| 196 | return usage(arg0); | ||
| 197 | } | 269 | } |
| 198 | } | 270 | } |
| 271 | } else if (cmd == Cmd.None) { | ||
| 272 | if (mem.eql(u8, arg, "build-obj")) { | ||
| 273 | cmd = Cmd.Build; | ||
| 274 | build_kind = Module.Kind.Obj; | ||
| 275 | } else if (mem.eql(u8, arg, "build-exe")) { | ||
| 276 | cmd = Cmd.Build; | ||
| 277 | build_kind = Module.Kind.Exe; | ||
| 278 | } else if (mem.eql(u8, arg, "build-lib")) { | ||
| 279 | cmd = Cmd.Build; | ||
| 280 | build_kind = Module.Kind.Lib; | ||
| 281 | } else if (mem.eql(u8, arg, "version")) { | ||
| 282 | cmd = Cmd.Version; | ||
| 283 | } else if (mem.eql(u8, arg, "zen")) { | ||
| 284 | cmd = Cmd.Zen; | ||
| 285 | } else if (mem.eql(u8, arg, "translate-c")) { | ||
| 286 | cmd = Cmd.TranslateC; | ||
| 287 | } else if (mem.eql(u8, arg, "test")) { | ||
| 288 | cmd = Cmd.Test; | ||
| 289 | build_kind = Module.Kind.Exe; | ||
| 290 | } else { | ||
| 291 | return badArgs("unrecognized command: {}", arg); | ||
| 292 | } | ||
| 293 | } else switch (cmd) { | ||
| 294 | Cmd.Build, Cmd.TranslateC, Cmd.Test => { | ||
| 295 | if (in_file_arg == null) { | ||
| 296 | in_file_arg = arg; | ||
| 297 | } else { | ||
| 298 | return badArgs("unexpected extra parameter: {}", arg); | ||
| 299 | } | ||
| 300 | }, | ||
| 301 | Cmd.Version, Cmd.Zen, Cmd.Targets => { | ||
| 302 | return badArgs("unexpected extra parameter: {}", arg); | ||
| 303 | }, | ||
| 304 | Cmd.None => unreachable, | ||
| 199 | } | 305 | } |
| 200 | } | 306 | } |
| 307 | |||
| 308 | target.initializeAll(); | ||
| 309 | |||
| 310 | // TODO | ||
| 311 | // ZigTarget alloc_target; | ||
| 312 | // ZigTarget *target; | ||
| 313 | // if (!target_arch && !target_os && !target_environ) { | ||
| 314 | // target = nullptr; | ||
| 315 | // } else { | ||
| 316 | // target = &alloc_target; | ||
| 317 | // get_unknown_target(target); | ||
| 318 | // if (target_arch) { | ||
| 319 | // if (parse_target_arch(target_arch, &target->arch)) { | ||
| 320 | // fprintf(stderr, "invalid --target-arch argument\n"); | ||
| 321 | // return usage(arg0); | ||
| 322 | // } | ||
| 323 | // } | ||
| 324 | // if (target_os) { | ||
| 325 | // if (parse_target_os(target_os, &target->os)) { | ||
| 326 | // fprintf(stderr, "invalid --target-os argument\n"); | ||
| 327 | // return usage(arg0); | ||
| 328 | // } | ||
| 329 | // } | ||
| 330 | // if (target_environ) { | ||
| 331 | // if (parse_target_environ(target_environ, &target->env_type)) { | ||
| 332 | // fprintf(stderr, "invalid --target-environ argument\n"); | ||
| 333 | // return usage(arg0); | ||
| 334 | // } | ||
| 335 | // } | ||
| 336 | // } | ||
| 337 | |||
| 338 | switch (cmd) { | ||
| 339 | Cmd.None => return badArgs("expected command"), | ||
| 340 | Cmd.Zen => return printZen(), | ||
| 341 | Cmd.Build, Cmd.Test, Cmd.TranslateC => { | ||
| 342 | if (cmd == Cmd.Build and in_file_arg == null and objects.len == 0 and asm_files.len == 0) { | ||
| 343 | return badArgs("expected source file argument or at least one --object or --assembly argument"); | ||
| 344 | } else if ((cmd == Cmd.TranslateC or cmd == Cmd.Test) and in_file_arg == null) { | ||
| 345 | return badArgs("expected source file argument"); | ||
| 346 | } else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) { | ||
| 347 | return badArgs("When building an object file, --object arguments are invalid"); | ||
| 348 | } | ||
| 349 | |||
| 350 | const root_name = switch (cmd) { | ||
| 351 | Cmd.Build, Cmd.TranslateC => x: { | ||
| 352 | if (out_name_arg) |out_name| { | ||
| 353 | break :x out_name; | ||
| 354 | } else if (in_file_arg) |in_file_path| { | ||
| 355 | const basename = os.path.basename(in_file_path); | ||
| 356 | var it = mem.split(basename, "."); | ||
| 357 | break :x it.next() ?? return badArgs("file name cannot be empty"); | ||
| 358 | } else { | ||
| 359 | return badArgs("--name [name] not provided and unable to infer"); | ||
| 360 | } | ||
| 361 | }, | ||
| 362 | Cmd.Test => "test", | ||
| 363 | else => unreachable, | ||
| 364 | }; | ||
| 365 | |||
| 366 | const zig_root_source_file = if (cmd == Cmd.TranslateC) null else in_file_arg; | ||
| 367 | |||
| 368 | const chosen_cache_dir = cache_dir_arg ?? default_zig_cache_name; | ||
| 369 | const full_cache_dir = %return os.path.resolve(allocator, ".", chosen_cache_dir); | ||
| 370 | defer allocator.free(full_cache_dir); | ||
| 371 | |||
| 372 | const zig_lib_dir = %return resolveZigLibDir(allocator, zig_install_prefix); | ||
| 373 | %defer allocator.free(zig_lib_dir); | ||
| 374 | |||
| 375 | const module = %return Module.create(allocator, root_name, zig_root_source_file, | ||
| 376 | Target.Native, build_kind, build_mode, zig_lib_dir, full_cache_dir); | ||
| 377 | defer module.destroy(); | ||
| 378 | |||
| 379 | module.version_major = ver_major; | ||
| 380 | module.version_minor = ver_minor; | ||
| 381 | module.version_patch = ver_patch; | ||
| 382 | |||
| 383 | module.is_test = cmd == Cmd.Test; | ||
| 384 | if (linker_script_arg) |linker_script| { | ||
| 385 | module.linker_script = linker_script; | ||
| 386 | } | ||
| 387 | module.each_lib_rpath = each_lib_rpath; | ||
| 388 | module.clang_argv = clang_argv.toSliceConst(); | ||
| 389 | module.llvm_argv = llvm_argv.toSliceConst(); | ||
| 390 | module.strip = strip; | ||
| 391 | module.is_static = is_static; | ||
| 392 | |||
| 393 | if (libc_lib_dir_arg) |libc_lib_dir| { | ||
| 394 | module.libc_lib_dir = libc_lib_dir; | ||
| 395 | } | ||
| 396 | if (libc_static_lib_dir_arg) |libc_static_lib_dir| { | ||
| 397 | module.libc_static_lib_dir = libc_static_lib_dir; | ||
| 398 | } | ||
| 399 | if (libc_include_dir_arg) |libc_include_dir| { | ||
| 400 | module.libc_include_dir = libc_include_dir; | ||
| 401 | } | ||
| 402 | if (msvc_lib_dir_arg) |msvc_lib_dir| { | ||
| 403 | module.msvc_lib_dir = msvc_lib_dir; | ||
| 404 | } | ||
| 405 | if (kernel32_lib_dir_arg) |kernel32_lib_dir| { | ||
| 406 | module.kernel32_lib_dir = kernel32_lib_dir; | ||
| 407 | } | ||
| 408 | if (dynamic_linker_arg) |dynamic_linker| { | ||
| 409 | module.dynamic_linker = dynamic_linker; | ||
| 410 | } | ||
| 411 | module.verbose_tokenize = verbose_tokenize; | ||
| 412 | module.verbose_ast_tree = verbose_ast_tree; | ||
| 413 | module.verbose_ast_fmt = verbose_ast_fmt; | ||
| 414 | module.verbose_link = verbose_link; | ||
| 415 | module.verbose_ir = verbose_ir; | ||
| 416 | module.verbose_llvm_ir = verbose_llvm_ir; | ||
| 417 | module.verbose_cimport = verbose_cimport; | ||
| 418 | |||
| 419 | module.err_color = color; | ||
| 420 | |||
| 421 | module.lib_dirs = lib_dirs.toSliceConst(); | ||
| 422 | module.darwin_frameworks = frameworks.toSliceConst(); | ||
| 423 | module.rpath_list = rpath_list.toSliceConst(); | ||
| 424 | |||
| 425 | for (link_libs.toSliceConst()) |name| { | ||
| 426 | _ = %return module.addLinkLib(name, true); | ||
| 427 | } | ||
| 428 | |||
| 429 | module.windows_subsystem_windows = mwindows; | ||
| 430 | module.windows_subsystem_console = mconsole; | ||
| 431 | module.linker_rdynamic = rdynamic; | ||
| 432 | |||
| 433 | if (mmacosx_version_min != null and mios_version_min != null) { | ||
| 434 | return badArgs("-mmacosx-version-min and -mios-version-min options not allowed together"); | ||
| 435 | } | ||
| 436 | |||
| 437 | if (mmacosx_version_min) |ver| { | ||
| 438 | module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver }; | ||
| 439 | } else if (mios_version_min) |ver| { | ||
| 440 | module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver }; | ||
| 441 | } | ||
| 442 | |||
| 443 | module.test_filters = test_filters.toSliceConst(); | ||
| 444 | module.test_name_prefix = test_name_prefix_arg; | ||
| 445 | module.out_h_path = out_file_h; | ||
| 446 | |||
| 447 | // TODO | ||
| 448 | //add_package(g, cur_pkg, g->root_package); | ||
| 449 | |||
| 450 | switch (cmd) { | ||
| 451 | Cmd.Build => { | ||
| 452 | module.emit_file_type = emit_file_type; | ||
| 453 | |||
| 454 | module.link_objects = objects.toSliceConst(); | ||
| 455 | module.assembly_files = asm_files.toSliceConst(); | ||
| 456 | |||
| 457 | %return module.build(); | ||
| 458 | %return module.link(out_file); | ||
| 459 | }, | ||
| 460 | Cmd.TranslateC => @panic("TODO translate-c"), | ||
| 461 | Cmd.Test => @panic("TODO test cmd"), | ||
| 462 | else => unreachable, | ||
| 463 | } | ||
| 464 | }, | ||
| 465 | Cmd.Version => @panic("TODO zig version"), | ||
| 466 | Cmd.Targets => @panic("TODO zig targets"), | ||
| 467 | } | ||
| 201 | } | 468 | } |
| 202 | 469 | ||
| 203 | fn printUsage(outstream: &io.OutStream) -> %void { | 470 | fn printUsage(stream: &io.OutStream) -> %void { |
| 204 | %return outstream.print("Usage: {} [command] [options]\n", arg0); | 471 | %return stream.write( |
| 205 | %return outstream.write( | 472 | \\Usage: zig [command] [options] |
| 473 | \\ | ||
| 206 | \\Commands: | 474 | \\Commands: |
| 207 | \\ build build project from build.zig | 475 | \\ build build project from build.zig |
| 208 | \\ build-exe [source] create executable from source or object files | 476 | \\ build-exe [source] create executable from source or object files |
| ... | @@ -217,6 +485,7 @@ fn printUsage(outstream: &io.OutStream) -> %void { | ... | @@ -217,6 +485,7 @@ fn printUsage(outstream: &io.OutStream) -> %void { |
| 217 | \\ --assembly [source] add assembly file to build | 485 | \\ --assembly [source] add assembly file to build |
| 218 | \\ --cache-dir [path] override the cache directory | 486 | \\ --cache-dir [path] override the cache directory |
| 219 | \\ --color [auto|off|on] enable or disable colored error messages | 487 | \\ --color [auto|off|on] enable or disable colored error messages |
| 488 | \\ --emit [filetype] emit a specific file format as compilation output | ||
| 220 | \\ --enable-timing-info print timing diagnostics | 489 | \\ --enable-timing-info print timing diagnostics |
| 221 | \\ --libc-include-dir [path] directory where libc stdlib.h resides | 490 | \\ --libc-include-dir [path] directory where libc stdlib.h resides |
| 222 | \\ --name [name] override output name | 491 | \\ --name [name] override output name |
| ... | @@ -231,9 +500,13 @@ fn printUsage(outstream: &io.OutStream) -> %void { | ... | @@ -231,9 +500,13 @@ fn printUsage(outstream: &io.OutStream) -> %void { |
| 231 | \\ --target-arch [name] specify target architecture | 500 | \\ --target-arch [name] specify target architecture |
| 232 | \\ --target-environ [name] specify target environment | 501 | \\ --target-environ [name] specify target environment |
| 233 | \\ --target-os [name] specify target operating system | 502 | \\ --target-os [name] specify target operating system |
| 234 | \\ --verbose turn on compiler debug output | 503 | \\ --verbose-tokenize enable compiler debug info: tokenization |
| 235 | \\ --verbose-link turn on compiler debug output for linking only | 504 | \\ --verbose-ast-tree enable compiler debug info: parsing into an AST (treeview) |
| 236 | \\ --verbose-ir turn on compiler debug output for IR only | 505 | \\ --verbose-ast-fmt enable compiler debug info: parsing into an AST (render source) |
| 506 | \\ --verbose-cimport enable compiler debug info: C imports | ||
| 507 | \\ --verbose-ir enable compiler debug info: Zig IR | ||
| 508 | \\ --verbose-llvm-ir enable compiler debug info: LLVM IR | ||
| 509 | \\ --verbose-link enable compiler debug info: linking | ||
| 237 | \\ --zig-install-prefix [path] override directory where zig thinks it is installed | 510 | \\ --zig-install-prefix [path] override directory where zig thinks it is installed |
| 238 | \\ -dirafter [dir] same as -isystem but do it last | 511 | \\ -dirafter [dir] same as -isystem but do it last |
| 239 | \\ -isystem [dir] add additional search path for other .h files | 512 | \\ -isystem [dir] add additional search path for other .h files |
| ... | @@ -255,7 +528,6 @@ fn printUsage(outstream: &io.OutStream) -> %void { | ... | @@ -255,7 +528,6 @@ fn printUsage(outstream: &io.OutStream) -> %void { |
| 255 | \\ -rpath [path] add directory to the runtime library search path | 528 | \\ -rpath [path] add directory to the runtime library search path |
| 256 | \\ -mconsole (windows) --subsystem console to the linker | 529 | \\ -mconsole (windows) --subsystem console to the linker |
| 257 | \\ -mwindows (windows) --subsystem windows to the linker | 530 | \\ -mwindows (windows) --subsystem windows to the linker |
| 258 | \\ -municode (windows) link with unicode | ||
| 259 | \\ -framework [name] (darwin) link against framework | 531 | \\ -framework [name] (darwin) link against framework |
| 260 | \\ -mios-version-min [ver] (darwin) set iOS deployment target | 532 | \\ -mios-version-min [ver] (darwin) set iOS deployment target |
| 261 | \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target | 533 | \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target |
| ... | @@ -271,17 +543,81 @@ fn printUsage(outstream: &io.OutStream) -> %void { | ... | @@ -271,17 +543,81 @@ fn printUsage(outstream: &io.OutStream) -> %void { |
| 271 | ); | 543 | ); |
| 272 | } | 544 | } |
| 273 | 545 | ||
| 274 | const ZIG_ZEN = | 546 | fn printZen() -> %void { |
| 275 | \\ * Communicate intent precisely. | 547 | var stdout_file = %return io.getStdErr(); |
| 276 | \\ * Edge cases matter. | 548 | %return stdout_file.write( |
| 277 | \\ * Favor reading code over writing code. | 549 | \\ |
| 278 | \\ * Only one obvious way to do things. | 550 | \\ * Communicate intent precisely. |
| 279 | \\ * Runtime crashes are better than bugs. | 551 | \\ * Edge cases matter. |
| 280 | \\ * Compile errors are better than runtime crashes. | 552 | \\ * Favor reading code over writing code. |
| 281 | \\ * Incremental improvements. | 553 | \\ * Only one obvious way to do things. |
| 282 | \\ * Avoid local maximums. | 554 | \\ * Runtime crashes are better than bugs. |
| 283 | \\ * Reduce the amount one must remember. | 555 | \\ * Compile errors are better than runtime crashes. |
| 284 | \\ * Minimize energy spent on coding style. | 556 | \\ * Incremental improvements. |
| 285 | \\ * Together we serve end users. | 557 | \\ * Avoid local maximums. |
| 286 | \\ | 558 | \\ * Reduce the amount one must remember. |
| 287 | ; | 559 | \\ * Minimize energy spent on coding style. |
| 560 | \\ * Together we serve end users. | ||
| 561 | \\ | ||
| 562 | \\ | ||
| 563 | ); | ||
| 564 | } | ||
| 565 | |||
| 566 | /// Caller must free result | ||
| 567 | fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) -> %[]u8 { | ||
| 568 | if (zig_install_prefix_arg) |zig_install_prefix| { | ||
| 569 | return testZigInstallPrefix(allocator, zig_install_prefix) %% |err| { | ||
| 570 | warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err)); | ||
| 571 | return error.ZigInstallationNotFound; | ||
| 572 | }; | ||
| 573 | } else { | ||
| 574 | return findZigLibDir(allocator) %% |err| { | ||
| 575 | warn("Unable to find zig lib directory: {}.\nReinstall Zig or use --zig-install-prefix.\n", | ||
| 576 | @errorName(err)); | ||
| 577 | return error.ZigLibDirNotFound; | ||
| 578 | }; | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | /// Caller must free result | ||
| 583 | fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) -> %[]u8 { | ||
| 584 | const test_zig_dir = %return os.path.join(allocator, test_path, "lib", "zig"); | ||
| 585 | %defer allocator.free(test_zig_dir); | ||
| 586 | |||
| 587 | const test_index_file = %return os.path.join(allocator, test_zig_dir, "std", "index.zig"); | ||
| 588 | defer allocator.free(test_index_file); | ||
| 589 | |||
| 590 | var file = %return io.File.openRead(test_index_file, allocator); | ||
| 591 | file.close(); | ||
| 592 | |||
| 593 | return test_zig_dir; | ||
| 594 | } | ||
| 595 | |||
| 596 | /// Caller must free result | ||
| 597 | fn findZigLibDir(allocator: &mem.Allocator) -> %[]u8 { | ||
| 598 | const self_exe_path = %return os.selfExeDirPath(allocator); | ||
| 599 | defer allocator.free(self_exe_path); | ||
| 600 | |||
| 601 | var cur_path: []const u8 = self_exe_path; | ||
| 602 | while (true) { | ||
| 603 | const test_dir = os.path.dirname(cur_path); | ||
| 604 | |||
| 605 | if (mem.eql(u8, test_dir, cur_path)) { | ||
| 606 | break; | ||
| 607 | } | ||
| 608 | |||
| 609 | return testZigInstallPrefix(allocator, test_dir) %% |err| { | ||
| 610 | cur_path = test_dir; | ||
| 611 | continue; | ||
| 612 | }; | ||
| 613 | } | ||
| 614 | |||
| 615 | // TODO look in hard coded installation path from configuration | ||
| 616 | //if (ZIG_INSTALL_PREFIX != nullptr) { | ||
| 617 | // if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) { | ||
| 618 | // return 0; | ||
| 619 | // } | ||
| 620 | //} | ||
| 621 | |||
| 622 | return error.FileNotFound; | ||
| 623 | } |
src-self-hosted/module.zig created+295| ... | @@ -0,0 +1,295 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const os = std.os; | ||
| 3 | const io = std.io; | ||
| 4 | const mem = std.mem; | ||
| 5 | const Buffer = std.Buffer; | ||
| 6 | const llvm = @import("llvm.zig"); | ||
| 7 | const c = @import("c.zig"); | ||
| 8 | const builtin = @import("builtin"); | ||
| 9 | const Target = @import("target.zig").Target; | ||
| 10 | const warn = std.debug.warn; | ||
| 11 | const Tokenizer = @import("tokenizer.zig").Tokenizer; | ||
| 12 | const Token = @import("tokenizer.zig").Token; | ||
| 13 | const Parser = @import("parser.zig").Parser; | ||
| 14 | const ArrayList = std.ArrayList; | ||
| 15 | |||
| 16 | pub const Module = struct { | ||
| 17 | allocator: &mem.Allocator, | ||
| 18 | name: Buffer, | ||
| 19 | root_src_path: ?[]const u8, | ||
| 20 | module: llvm.ModuleRef, | ||
| 21 | context: llvm.ContextRef, | ||
| 22 | builder: llvm.BuilderRef, | ||
| 23 | target: Target, | ||
| 24 | build_mode: builtin.Mode, | ||
| 25 | zig_lib_dir: []const u8, | ||
| 26 | |||
| 27 | version_major: u32, | ||
| 28 | version_minor: u32, | ||
| 29 | version_patch: u32, | ||
| 30 | |||
| 31 | linker_script: ?[]const u8, | ||
| 32 | cache_dir: []const u8, | ||
| 33 | libc_lib_dir: ?[]const u8, | ||
| 34 | libc_static_lib_dir: ?[]const u8, | ||
| 35 | libc_include_dir: ?[]const u8, | ||
| 36 | msvc_lib_dir: ?[]const u8, | ||
| 37 | kernel32_lib_dir: ?[]const u8, | ||
| 38 | dynamic_linker: ?[]const u8, | ||
| 39 | out_h_path: ?[]const u8, | ||
| 40 | |||
| 41 | is_test: bool, | ||
| 42 | each_lib_rpath: bool, | ||
| 43 | strip: bool, | ||
| 44 | is_static: bool, | ||
| 45 | linker_rdynamic: bool, | ||
| 46 | |||
| 47 | clang_argv: []const []const u8, | ||
| 48 | llvm_argv: []const []const u8, | ||
| 49 | lib_dirs: []const []const u8, | ||
| 50 | rpath_list: []const []const u8, | ||
| 51 | assembly_files: []const []const u8, | ||
| 52 | link_objects: []const []const u8, | ||
| 53 | |||
| 54 | windows_subsystem_windows: bool, | ||
| 55 | windows_subsystem_console: bool, | ||
| 56 | |||
| 57 | link_libs_list: ArrayList(&LinkLib), | ||
| 58 | libc_link_lib: ?&LinkLib, | ||
| 59 | |||
| 60 | err_color: ErrColor, | ||
| 61 | |||
| 62 | verbose_tokenize: bool, | ||
| 63 | verbose_ast_tree: bool, | ||
| 64 | verbose_ast_fmt: bool, | ||
| 65 | verbose_cimport: bool, | ||
| 66 | verbose_ir: bool, | ||
| 67 | verbose_llvm_ir: bool, | ||
| 68 | verbose_link: bool, | ||
| 69 | |||
| 70 | darwin_frameworks: []const []const u8, | ||
| 71 | darwin_version_min: DarwinVersionMin, | ||
| 72 | |||
| 73 | test_filters: []const []const u8, | ||
| 74 | test_name_prefix: ?[]const u8, | ||
| 75 | |||
| 76 | emit_file_type: Emit, | ||
| 77 | |||
| 78 | kind: Kind, | ||
| 79 | |||
| 80 | pub const DarwinVersionMin = union(enum) { | ||
| 81 | None, | ||
| 82 | MacOS: []const u8, | ||
| 83 | Ios: []const u8, | ||
| 84 | }; | ||
| 85 | |||
| 86 | pub const Kind = enum { | ||
| 87 | Exe, | ||
| 88 | Lib, | ||
| 89 | Obj, | ||
| 90 | }; | ||
| 91 | |||
| 92 | pub const ErrColor = enum { | ||
| 93 | Auto, | ||
| 94 | Off, | ||
| 95 | On, | ||
| 96 | }; | ||
| 97 | |||
| 98 | pub const LinkLib = struct { | ||
| 99 | name: []const u8, | ||
| 100 | path: ?[]const u8, | ||
| 101 | /// the list of symbols we depend on from this lib | ||
| 102 | symbols: ArrayList([]u8), | ||
| 103 | provided_explicitly: bool, | ||
| 104 | }; | ||
| 105 | |||
| 106 | pub const Emit = enum { | ||
| 107 | Binary, | ||
| 108 | Assembly, | ||
| 109 | LlvmIr, | ||
| 110 | }; | ||
| 111 | |||
| 112 | pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target, | ||
| 113 | kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) -> %&Module | ||
| 114 | { | ||
| 115 | var name_buffer = %return Buffer.init(allocator, name); | ||
| 116 | %defer name_buffer.deinit(); | ||
| 117 | |||
| 118 | const context = c.LLVMContextCreate() ?? return error.OutOfMemory; | ||
| 119 | %defer c.LLVMContextDispose(context); | ||
| 120 | |||
| 121 | const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) ?? return error.OutOfMemory; | ||
| 122 | %defer c.LLVMDisposeModule(module); | ||
| 123 | |||
| 124 | const builder = c.LLVMCreateBuilderInContext(context) ?? return error.OutOfMemory; | ||
| 125 | %defer c.LLVMDisposeBuilder(builder); | ||
| 126 | |||
| 127 | const module_ptr = %return allocator.create(Module); | ||
| 128 | %defer allocator.destroy(module_ptr); | ||
| 129 | |||
| 130 | *module_ptr = Module { | ||
| 131 | .allocator = allocator, | ||
| 132 | .name = name_buffer, | ||
| 133 | .root_src_path = root_src_path, | ||
| 134 | .module = module, | ||
| 135 | .context = context, | ||
| 136 | .builder = builder, | ||
| 137 | .target = *target, | ||
| 138 | .kind = kind, | ||
| 139 | .build_mode = build_mode, | ||
| 140 | .zig_lib_dir = zig_lib_dir, | ||
| 141 | .cache_dir = cache_dir, | ||
| 142 | |||
| 143 | .version_major = 0, | ||
| 144 | .version_minor = 0, | ||
| 145 | .version_patch = 0, | ||
| 146 | |||
| 147 | .verbose_tokenize = false, | ||
| 148 | .verbose_ast_tree = false, | ||
| 149 | .verbose_ast_fmt = false, | ||
| 150 | .verbose_cimport = false, | ||
| 151 | .verbose_ir = false, | ||
| 152 | .verbose_llvm_ir = false, | ||
| 153 | .verbose_link = false, | ||
| 154 | |||
| 155 | .linker_script = null, | ||
| 156 | .libc_lib_dir = null, | ||
| 157 | .libc_static_lib_dir = null, | ||
| 158 | .libc_include_dir = null, | ||
| 159 | .msvc_lib_dir = null, | ||
| 160 | .kernel32_lib_dir = null, | ||
| 161 | .dynamic_linker = null, | ||
| 162 | .out_h_path = null, | ||
| 163 | .is_test = false, | ||
| 164 | .each_lib_rpath = false, | ||
| 165 | .strip = false, | ||
| 166 | .is_static = false, | ||
| 167 | .linker_rdynamic = false, | ||
| 168 | .clang_argv = [][]const u8{}, | ||
| 169 | .llvm_argv = [][]const u8{}, | ||
| 170 | .lib_dirs = [][]const u8{}, | ||
| 171 | .rpath_list = [][]const u8{}, | ||
| 172 | .assembly_files = [][]const u8{}, | ||
| 173 | .link_objects = [][]const u8{}, | ||
| 174 | .windows_subsystem_windows = false, | ||
| 175 | .windows_subsystem_console = false, | ||
| 176 | .link_libs_list = ArrayList(&LinkLib).init(allocator), | ||
| 177 | .libc_link_lib = null, | ||
| 178 | .err_color = ErrColor.Auto, | ||
| 179 | .darwin_frameworks = [][]const u8{}, | ||
| 180 | .darwin_version_min = DarwinVersionMin.None, | ||
| 181 | .test_filters = [][]const u8{}, | ||
| 182 | .test_name_prefix = null, | ||
| 183 | .emit_file_type = Emit.Binary, | ||
| 184 | }; | ||
| 185 | return module_ptr; | ||
| 186 | } | ||
| 187 | |||
| 188 | fn dump(self: &Module) { | ||
| 189 | c.LLVMDumpModule(self.module); | ||
| 190 | } | ||
| 191 | |||
| 192 | pub fn destroy(self: &Module) { | ||
| 193 | c.LLVMDisposeBuilder(self.builder); | ||
| 194 | c.LLVMDisposeModule(self.module); | ||
| 195 | c.LLVMContextDispose(self.context); | ||
| 196 | self.name.deinit(); | ||
| 197 | |||
| 198 | self.allocator.destroy(self); | ||
| 199 | } | ||
| 200 | |||
| 201 | pub fn build(self: &Module) -> %void { | ||
| 202 | const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path"); | ||
| 203 | const root_src_real_path = os.path.real(self.allocator, root_src_path) %% |err| { | ||
| 204 | %return printError("unable to open '{}': {}", root_src_path, err); | ||
| 205 | return err; | ||
| 206 | }; | ||
| 207 | %defer self.allocator.free(root_src_real_path); | ||
| 208 | |||
| 209 | const source_code = io.readFileAlloc(root_src_real_path, self.allocator) %% |err| { | ||
| 210 | %return printError("unable to open '{}': {}", root_src_real_path, err); | ||
| 211 | return err; | ||
| 212 | }; | ||
| 213 | %defer self.allocator.free(source_code); | ||
| 214 | |||
| 215 | warn("====input:====\n"); | ||
| 216 | |||
| 217 | warn("{}", source_code); | ||
| 218 | |||
| 219 | warn("====tokenization:====\n"); | ||
| 220 | { | ||
| 221 | var tokenizer = Tokenizer.init(source_code); | ||
| 222 | while (true) { | ||
| 223 | const token = tokenizer.next(); | ||
| 224 | tokenizer.dump(token); | ||
| 225 | if (token.id == Token.Id.Eof) { | ||
| 226 | break; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | warn("====parse:====\n"); | ||
| 232 | |||
| 233 | var tokenizer = Tokenizer.init(source_code); | ||
| 234 | var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path); | ||
| 235 | defer parser.deinit(); | ||
| 236 | |||
| 237 | const root_node = %return parser.parse(); | ||
| 238 | defer parser.freeAst(root_node); | ||
| 239 | |||
| 240 | var stderr_file = %return std.io.getStdErr(); | ||
| 241 | var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file); | ||
| 242 | const out_stream = &stderr_file_out_stream.stream; | ||
| 243 | %return parser.renderAst(out_stream, root_node); | ||
| 244 | |||
| 245 | warn("====fmt:====\n"); | ||
| 246 | %return parser.renderSource(out_stream, root_node); | ||
| 247 | |||
| 248 | warn("====ir:====\n"); | ||
| 249 | warn("TODO\n\n"); | ||
| 250 | |||
| 251 | warn("====llvm ir:====\n"); | ||
| 252 | self.dump(); | ||
| 253 | |||
| 254 | } | ||
| 255 | |||
| 256 | pub fn link(self: &Module, out_file: ?[]const u8) -> %void { | ||
| 257 | warn("TODO link"); | ||
| 258 | } | ||
| 259 | |||
| 260 | pub fn addLinkLib(self: &Module, name: []const u8, provided_explicitly: bool) -> %&LinkLib { | ||
| 261 | const is_libc = mem.eql(u8, name, "c"); | ||
| 262 | |||
| 263 | if (is_libc) { | ||
| 264 | if (self.libc_link_lib) |libc_link_lib| { | ||
| 265 | return libc_link_lib; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | for (self.link_libs_list.toSliceConst()) |existing_lib| { | ||
| 270 | if (mem.eql(u8, name, existing_lib.name)) { | ||
| 271 | return existing_lib; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | const link_lib = %return self.allocator.create(LinkLib); | ||
| 276 | *link_lib = LinkLib { | ||
| 277 | .name = name, | ||
| 278 | .path = null, | ||
| 279 | .provided_explicitly = provided_explicitly, | ||
| 280 | .symbols = ArrayList([]u8).init(self.allocator), | ||
| 281 | }; | ||
| 282 | %return self.link_libs_list.append(link_lib); | ||
| 283 | if (is_libc) { | ||
| 284 | self.libc_link_lib = link_lib; | ||
| 285 | } | ||
| 286 | return link_lib; | ||
| 287 | } | ||
| 288 | }; | ||
| 289 | |||
| 290 | fn printError(comptime format: []const u8, args: ...) -> %void { | ||
| 291 | var stderr_file = %return std.io.getStdErr(); | ||
| 292 | var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file); | ||
| 293 | const out_stream = &stderr_file_out_stream.stream; | ||
| 294 | %return out_stream.print(format, args); | ||
| 295 | } | ||
src-self-hosted/parser.zig created+1203| ... | @@ -0,0 +1,1203 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const ArrayList = std.ArrayList; | ||
| 4 | const mem = std.mem; | ||
| 5 | const ast = @import("ast.zig"); | ||
| 6 | const Tokenizer = @import("tokenizer.zig").Tokenizer; | ||
| 7 | const Token = @import("tokenizer.zig").Token; | ||
| 8 | const builtin = @import("builtin"); | ||
| 9 | const io = std.io; | ||
| 10 | |||
| 11 | // TODO when we make parse errors into error types instead of printing directly, | ||
| 12 | // get rid of this | ||
| 13 | const warn = std.debug.warn; | ||
| 14 | |||
| 15 | error ParseError; | ||
| 16 | |||
| 17 | pub const Parser = struct { | ||
| 18 | allocator: &mem.Allocator, | ||
| 19 | tokenizer: &Tokenizer, | ||
| 20 | put_back_tokens: [2]Token, | ||
| 21 | put_back_count: usize, | ||
| 22 | source_file_name: []const u8, | ||
| 23 | cleanup_root_node: ?&ast.NodeRoot, | ||
| 24 | |||
| 25 | // This memory contents are used only during a function call. It's used to repurpose memory; | ||
| 26 | // specifically so that freeAst can be guaranteed to succeed. | ||
| 27 | const utility_bytes_align = @alignOf( union { a: RenderAstFrame, b: State, c: RenderState } ); | ||
| 28 | utility_bytes: []align(utility_bytes_align) u8, | ||
| 29 | |||
| 30 | pub fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) -> Parser { | ||
| 31 | return Parser { | ||
| 32 | .allocator = allocator, | ||
| 33 | .tokenizer = tokenizer, | ||
| 34 | .put_back_tokens = undefined, | ||
| 35 | .put_back_count = 0, | ||
| 36 | .source_file_name = source_file_name, | ||
| 37 | .utility_bytes = []align(utility_bytes_align) u8{}, | ||
| 38 | .cleanup_root_node = null, | ||
| 39 | }; | ||
| 40 | } | ||
| 41 | |||
| 42 | pub fn deinit(self: &Parser) { | ||
| 43 | assert(self.cleanup_root_node == null); | ||
| 44 | self.allocator.free(self.utility_bytes); | ||
| 45 | } | ||
| 46 | |||
| 47 | const TopLevelDeclCtx = struct { | ||
| 48 | visib_token: ?Token, | ||
| 49 | extern_token: ?Token, | ||
| 50 | }; | ||
| 51 | |||
| 52 | const DestPtr = union(enum) { | ||
| 53 | Field: &&ast.Node, | ||
| 54 | NullableField: &?&ast.Node, | ||
| 55 | List: &ArrayList(&ast.Node), | ||
| 56 | |||
| 57 | pub fn store(self: &const DestPtr, value: &ast.Node) -> %void { | ||
| 58 | switch (*self) { | ||
| 59 | DestPtr.Field => |ptr| *ptr = value, | ||
| 60 | DestPtr.NullableField => |ptr| *ptr = value, | ||
| 61 | DestPtr.List => |list| %return list.append(value), | ||
| 62 | } | ||
| 63 | } | ||
| 64 | }; | ||
| 65 | |||
| 66 | const State = union(enum) { | ||
| 67 | TopLevel, | ||
| 68 | TopLevelExtern: ?Token, | ||
| 69 | TopLevelDecl: TopLevelDeclCtx, | ||
| 70 | Expression: DestPtr, | ||
| 71 | ExpectOperand, | ||
| 72 | Operand: &ast.Node, | ||
| 73 | AfterOperand, | ||
| 74 | InfixOp: &ast.NodeInfixOp, | ||
| 75 | PrefixOp: &ast.NodePrefixOp, | ||
| 76 | AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo, | ||
| 77 | TypeExpr: DestPtr, | ||
| 78 | VarDecl: &ast.NodeVarDecl, | ||
| 79 | VarDeclAlign: &ast.NodeVarDecl, | ||
| 80 | VarDeclEq: &ast.NodeVarDecl, | ||
| 81 | ExpectToken: @TagType(Token.Id), | ||
| 82 | FnProto: &ast.NodeFnProto, | ||
| 83 | FnProtoAlign: &ast.NodeFnProto, | ||
| 84 | ParamDecl: &ast.NodeFnProto, | ||
| 85 | ParamDeclComma, | ||
| 86 | FnDef: &ast.NodeFnProto, | ||
| 87 | Block: &ast.NodeBlock, | ||
| 88 | Statement: &ast.NodeBlock, | ||
| 89 | }; | ||
| 90 | |||
| 91 | pub fn freeAst(self: &Parser, root_node: &ast.NodeRoot) { | ||
| 92 | // utility_bytes is big enough to do this iteration since we were able to do | ||
| 93 | // the parsing in the first place | ||
| 94 | comptime assert(@sizeOf(State) >= @sizeOf(&ast.Node)); | ||
| 95 | |||
| 96 | var stack = self.initUtilityArrayList(&ast.Node); | ||
| 97 | defer self.deinitUtilityArrayList(stack); | ||
| 98 | |||
| 99 | stack.append(&root_node.base) %% unreachable; | ||
| 100 | while (stack.popOrNull()) |node| { | ||
| 101 | var i: usize = 0; | ||
| 102 | while (node.iterate(i)) |child| : (i += 1) { | ||
| 103 | if (child.iterate(0) != null) { | ||
| 104 | stack.append(child) %% unreachable; | ||
| 105 | } else { | ||
| 106 | child.destroy(self.allocator); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | node.destroy(self.allocator); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | pub fn parse(self: &Parser) -> %&ast.NodeRoot { | ||
| 114 | const result = self.parseInner() %% |err| x: { | ||
| 115 | if (self.cleanup_root_node) |root_node| { | ||
| 116 | self.freeAst(root_node); | ||
| 117 | } | ||
| 118 | break :x err; | ||
| 119 | }; | ||
| 120 | self.cleanup_root_node = null; | ||
| 121 | return result; | ||
| 122 | } | ||
| 123 | |||
| 124 | pub fn parseInner(self: &Parser) -> %&ast.NodeRoot { | ||
| 125 | var stack = self.initUtilityArrayList(State); | ||
| 126 | defer self.deinitUtilityArrayList(stack); | ||
| 127 | |||
| 128 | const root_node = x: { | ||
| 129 | const root_node = %return self.createRoot(); | ||
| 130 | %defer self.allocator.destroy(root_node); | ||
| 131 | // This stack append has to succeed for freeAst to work | ||
| 132 | %return stack.append(State.TopLevel); | ||
| 133 | break :x root_node; | ||
| 134 | }; | ||
| 135 | assert(self.cleanup_root_node == null); | ||
| 136 | self.cleanup_root_node = root_node; | ||
| 137 | |||
| 138 | while (true) { | ||
| 139 | //{ | ||
| 140 | // const token = self.getNextToken(); | ||
| 141 | // warn("{} ", @tagName(token.id)); | ||
| 142 | // self.putBackToken(token); | ||
| 143 | // var i: usize = stack.len; | ||
| 144 | // while (i != 0) { | ||
| 145 | // i -= 1; | ||
| 146 | // warn("{} ", @tagName(stack.items[i])); | ||
| 147 | // } | ||
| 148 | // warn("\n"); | ||
| 149 | //} | ||
| 150 | |||
| 151 | // This gives us 1 free append that can't fail | ||
| 152 | const state = stack.pop(); | ||
| 153 | |||
| 154 | switch (state) { | ||
| 155 | State.TopLevel => { | ||
| 156 | const token = self.getNextToken(); | ||
| 157 | switch (token.id) { | ||
| 158 | Token.Id.Keyword_pub, Token.Id.Keyword_export => { | ||
| 159 | stack.append(State { .TopLevelExtern = token }) %% unreachable; | ||
| 160 | continue; | ||
| 161 | }, | ||
| 162 | Token.Id.Eof => return root_node, | ||
| 163 | else => { | ||
| 164 | self.putBackToken(token); | ||
| 165 | // TODO shouldn't need this cast | ||
| 166 | stack.append(State { .TopLevelExtern = null }) %% unreachable; | ||
| 167 | continue; | ||
| 168 | }, | ||
| 169 | } | ||
| 170 | }, | ||
| 171 | State.TopLevelExtern => |visib_token| { | ||
| 172 | const token = self.getNextToken(); | ||
| 173 | if (token.id == Token.Id.Keyword_extern) { | ||
| 174 | stack.append(State { | ||
| 175 | .TopLevelDecl = TopLevelDeclCtx { | ||
| 176 | .visib_token = visib_token, | ||
| 177 | .extern_token = token, | ||
| 178 | }, | ||
| 179 | }) %% unreachable; | ||
| 180 | continue; | ||
| 181 | } | ||
| 182 | self.putBackToken(token); | ||
| 183 | stack.append(State { | ||
| 184 | .TopLevelDecl = TopLevelDeclCtx { | ||
| 185 | .visib_token = visib_token, | ||
| 186 | .extern_token = null, | ||
| 187 | }, | ||
| 188 | }) %% unreachable; | ||
| 189 | continue; | ||
| 190 | }, | ||
| 191 | State.TopLevelDecl => |ctx| { | ||
| 192 | const token = self.getNextToken(); | ||
| 193 | switch (token.id) { | ||
| 194 | Token.Id.Keyword_var, Token.Id.Keyword_const => { | ||
| 195 | stack.append(State.TopLevel) %% unreachable; | ||
| 196 | // TODO shouldn't need these casts | ||
| 197 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, ctx.visib_token, | ||
| 198 | token, (?Token)(null), ctx.extern_token); | ||
| 199 | %return stack.append(State { .VarDecl = var_decl_node }); | ||
| 200 | continue; | ||
| 201 | }, | ||
| 202 | Token.Id.Keyword_fn => { | ||
| 203 | stack.append(State.TopLevel) %% unreachable; | ||
| 204 | // TODO shouldn't need these casts | ||
| 205 | const fn_proto = %return self.createAttachFnProto(&root_node.decls, token, | ||
| 206 | ctx.extern_token, (?Token)(null), (?Token)(null), (?Token)(null)); | ||
| 207 | %return stack.append(State { .FnDef = fn_proto }); | ||
| 208 | %return stack.append(State { .FnProto = fn_proto }); | ||
| 209 | continue; | ||
| 210 | }, | ||
| 211 | Token.Id.StringLiteral => { | ||
| 212 | @panic("TODO extern with string literal"); | ||
| 213 | }, | ||
| 214 | Token.Id.Keyword_coldcc, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => { | ||
| 215 | stack.append(State.TopLevel) %% unreachable; | ||
| 216 | const fn_token = %return self.eatToken(Token.Id.Keyword_fn); | ||
| 217 | // TODO shouldn't need this cast | ||
| 218 | const fn_proto = %return self.createAttachFnProto(&root_node.decls, fn_token, | ||
| 219 | ctx.extern_token, (?Token)(token), (?Token)(null), (?Token)(null)); | ||
| 220 | %return stack.append(State { .FnDef = fn_proto }); | ||
| 221 | %return stack.append(State { .FnProto = fn_proto }); | ||
| 222 | continue; | ||
| 223 | }, | ||
| 224 | else => return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id)), | ||
| 225 | } | ||
| 226 | }, | ||
| 227 | State.VarDecl => |var_decl| { | ||
| 228 | var_decl.name_token = %return self.eatToken(Token.Id.Identifier); | ||
| 229 | stack.append(State { .VarDeclAlign = var_decl }) %% unreachable; | ||
| 230 | |||
| 231 | const next_token = self.getNextToken(); | ||
| 232 | if (next_token.id == Token.Id.Colon) { | ||
| 233 | %return stack.append(State { .TypeExpr = DestPtr {.NullableField = &var_decl.type_node} }); | ||
| 234 | continue; | ||
| 235 | } | ||
| 236 | |||
| 237 | self.putBackToken(next_token); | ||
| 238 | continue; | ||
| 239 | }, | ||
| 240 | State.VarDeclAlign => |var_decl| { | ||
| 241 | stack.append(State { .VarDeclEq = var_decl }) %% unreachable; | ||
| 242 | |||
| 243 | const next_token = self.getNextToken(); | ||
| 244 | if (next_token.id == Token.Id.Keyword_align) { | ||
| 245 | _ = %return self.eatToken(Token.Id.LParen); | ||
| 246 | %return stack.append(State { .ExpectToken = Token.Id.RParen }); | ||
| 247 | %return stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} }); | ||
| 248 | continue; | ||
| 249 | } | ||
| 250 | |||
| 251 | self.putBackToken(next_token); | ||
| 252 | continue; | ||
| 253 | }, | ||
| 254 | State.VarDeclEq => |var_decl| { | ||
| 255 | const token = self.getNextToken(); | ||
| 256 | if (token.id == Token.Id.Equal) { | ||
| 257 | var_decl.eq_token = token; | ||
| 258 | stack.append(State { .ExpectToken = Token.Id.Semicolon }) %% unreachable; | ||
| 259 | %return stack.append(State { | ||
| 260 | .Expression = DestPtr {.NullableField = &var_decl.init_node}, | ||
| 261 | }); | ||
| 262 | continue; | ||
| 263 | } | ||
| 264 | if (token.id == Token.Id.Semicolon) { | ||
| 265 | continue; | ||
| 266 | } | ||
| 267 | return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id)); | ||
| 268 | }, | ||
| 269 | State.ExpectToken => |token_id| { | ||
| 270 | _ = %return self.eatToken(token_id); | ||
| 271 | continue; | ||
| 272 | }, | ||
| 273 | |||
| 274 | State.Expression => |dest_ptr| { | ||
| 275 | // save the dest_ptr for later | ||
| 276 | stack.append(state) %% unreachable; | ||
| 277 | %return stack.append(State.ExpectOperand); | ||
| 278 | continue; | ||
| 279 | }, | ||
| 280 | State.ExpectOperand => { | ||
| 281 | // we'll either get an operand (like 1 or x), | ||
| 282 | // or a prefix operator (like ~ or return). | ||
| 283 | const token = self.getNextToken(); | ||
| 284 | switch (token.id) { | ||
| 285 | Token.Id.Keyword_return => { | ||
| 286 | %return stack.append(State { .PrefixOp = %return self.createPrefixOp(token, | ||
| 287 | ast.NodePrefixOp.PrefixOp.Return) }); | ||
| 288 | %return stack.append(State.ExpectOperand); | ||
| 289 | continue; | ||
| 290 | }, | ||
| 291 | Token.Id.Ampersand => { | ||
| 292 | const prefix_op = %return self.createPrefixOp(token, ast.NodePrefixOp.PrefixOp{ | ||
| 293 | .AddrOf = ast.NodePrefixOp.AddrOfInfo { | ||
| 294 | .align_expr = null, | ||
| 295 | .bit_offset_start_token = null, | ||
| 296 | .bit_offset_end_token = null, | ||
| 297 | .const_token = null, | ||
| 298 | .volatile_token = null, | ||
| 299 | } | ||
| 300 | }); | ||
| 301 | %return stack.append(State { .PrefixOp = prefix_op }); | ||
| 302 | %return stack.append(State.ExpectOperand); | ||
| 303 | %return stack.append(State { .AddrOfModifiers = &prefix_op.op.AddrOf }); | ||
| 304 | continue; | ||
| 305 | }, | ||
| 306 | Token.Id.Identifier => { | ||
| 307 | %return stack.append(State { | ||
| 308 | .Operand = &(%return self.createIdentifier(token)).base | ||
| 309 | }); | ||
| 310 | %return stack.append(State.AfterOperand); | ||
| 311 | continue; | ||
| 312 | }, | ||
| 313 | Token.Id.IntegerLiteral => { | ||
| 314 | %return stack.append(State { | ||
| 315 | .Operand = &(%return self.createIntegerLiteral(token)).base | ||
| 316 | }); | ||
| 317 | %return stack.append(State.AfterOperand); | ||
| 318 | continue; | ||
| 319 | }, | ||
| 320 | Token.Id.FloatLiteral => { | ||
| 321 | %return stack.append(State { | ||
| 322 | .Operand = &(%return self.createFloatLiteral(token)).base | ||
| 323 | }); | ||
| 324 | %return stack.append(State.AfterOperand); | ||
| 325 | continue; | ||
| 326 | }, | ||
| 327 | else => return self.parseError(token, "expected primary expression, found {}", @tagName(token.id)), | ||
| 328 | } | ||
| 329 | }, | ||
| 330 | |||
| 331 | State.AfterOperand => { | ||
| 332 | // we'll either get an infix operator (like != or ^), | ||
| 333 | // or a postfix operator (like () or {}), | ||
| 334 | // otherwise this expression is done (like on a ; or else). | ||
| 335 | var token = self.getNextToken(); | ||
| 336 | switch (token.id) { | ||
| 337 | Token.Id.EqualEqual => { | ||
| 338 | %return stack.append(State { | ||
| 339 | .InfixOp = %return self.createInfixOp(token, ast.NodeInfixOp.InfixOp.EqualEqual) | ||
| 340 | }); | ||
| 341 | %return stack.append(State.ExpectOperand); | ||
| 342 | continue; | ||
| 343 | }, | ||
| 344 | Token.Id.BangEqual => { | ||
| 345 | %return stack.append(State { | ||
| 346 | .InfixOp = %return self.createInfixOp(token, ast.NodeInfixOp.InfixOp.BangEqual) | ||
| 347 | }); | ||
| 348 | %return stack.append(State.ExpectOperand); | ||
| 349 | continue; | ||
| 350 | }, | ||
| 351 | else => { | ||
| 352 | // no postfix/infix operator after this operand. | ||
| 353 | self.putBackToken(token); | ||
| 354 | // reduce the stack | ||
| 355 | var expression: &ast.Node = stack.pop().Operand; | ||
| 356 | while (true) { | ||
| 357 | switch (stack.pop()) { | ||
| 358 | State.Expression => |dest_ptr| { | ||
| 359 | // we're done | ||
| 360 | %return dest_ptr.store(expression); | ||
| 361 | break; | ||
| 362 | }, | ||
| 363 | State.InfixOp => |infix_op| { | ||
| 364 | infix_op.rhs = expression; | ||
| 365 | infix_op.lhs = stack.pop().Operand; | ||
| 366 | expression = &infix_op.base; | ||
| 367 | continue; | ||
| 368 | }, | ||
| 369 | State.PrefixOp => |prefix_op| { | ||
| 370 | prefix_op.rhs = expression; | ||
| 371 | expression = &prefix_op.base; | ||
| 372 | continue; | ||
| 373 | }, | ||
| 374 | else => unreachable, | ||
| 375 | } | ||
| 376 | } | ||
| 377 | continue; | ||
| 378 | }, | ||
| 379 | } | ||
| 380 | }, | ||
| 381 | |||
| 382 | State.AddrOfModifiers => |addr_of_info| { | ||
| 383 | var token = self.getNextToken(); | ||
| 384 | switch (token.id) { | ||
| 385 | Token.Id.Keyword_align => { | ||
| 386 | stack.append(state) %% unreachable; | ||
| 387 | if (addr_of_info.align_expr != null) return self.parseError(token, "multiple align qualifiers"); | ||
| 388 | _ = %return self.eatToken(Token.Id.LParen); | ||
| 389 | %return stack.append(State { .ExpectToken = Token.Id.RParen }); | ||
| 390 | %return stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} }); | ||
| 391 | continue; | ||
| 392 | }, | ||
| 393 | Token.Id.Keyword_const => { | ||
| 394 | stack.append(state) %% unreachable; | ||
| 395 | if (addr_of_info.const_token != null) return self.parseError(token, "duplicate qualifier: const"); | ||
| 396 | addr_of_info.const_token = token; | ||
| 397 | continue; | ||
| 398 | }, | ||
| 399 | Token.Id.Keyword_volatile => { | ||
| 400 | stack.append(state) %% unreachable; | ||
| 401 | if (addr_of_info.volatile_token != null) return self.parseError(token, "duplicate qualifier: volatile"); | ||
| 402 | addr_of_info.volatile_token = token; | ||
| 403 | continue; | ||
| 404 | }, | ||
| 405 | else => { | ||
| 406 | self.putBackToken(token); | ||
| 407 | continue; | ||
| 408 | }, | ||
| 409 | } | ||
| 410 | }, | ||
| 411 | |||
| 412 | State.TypeExpr => |dest_ptr| { | ||
| 413 | const token = self.getNextToken(); | ||
| 414 | if (token.id == Token.Id.Keyword_var) { | ||
| 415 | @panic("TODO param with type var"); | ||
| 416 | } | ||
| 417 | self.putBackToken(token); | ||
| 418 | |||
| 419 | stack.append(State { .Expression = dest_ptr }) %% unreachable; | ||
| 420 | continue; | ||
| 421 | }, | ||
| 422 | |||
| 423 | State.FnProto => |fn_proto| { | ||
| 424 | stack.append(State { .FnProtoAlign = fn_proto }) %% unreachable; | ||
| 425 | %return stack.append(State { .ParamDecl = fn_proto }); | ||
| 426 | %return stack.append(State { .ExpectToken = Token.Id.LParen }); | ||
| 427 | |||
| 428 | const next_token = self.getNextToken(); | ||
| 429 | if (next_token.id == Token.Id.Identifier) { | ||
| 430 | fn_proto.name_token = next_token; | ||
| 431 | continue; | ||
| 432 | } | ||
| 433 | self.putBackToken(next_token); | ||
| 434 | continue; | ||
| 435 | }, | ||
| 436 | |||
| 437 | State.FnProtoAlign => |fn_proto| { | ||
| 438 | const token = self.getNextToken(); | ||
| 439 | if (token.id == Token.Id.Keyword_align) { | ||
| 440 | @panic("TODO fn proto align"); | ||
| 441 | } | ||
| 442 | if (token.id == Token.Id.Arrow) { | ||
| 443 | stack.append(State { | ||
| 444 | .TypeExpr = DestPtr {.NullableField = &fn_proto.return_type}, | ||
| 445 | }) %% unreachable; | ||
| 446 | continue; | ||
| 447 | } else { | ||
| 448 | self.putBackToken(token); | ||
| 449 | continue; | ||
| 450 | } | ||
| 451 | }, | ||
| 452 | |||
| 453 | State.ParamDecl => |fn_proto| { | ||
| 454 | var token = self.getNextToken(); | ||
| 455 | if (token.id == Token.Id.RParen) { | ||
| 456 | continue; | ||
| 457 | } | ||
| 458 | const param_decl = %return self.createAttachParamDecl(&fn_proto.params); | ||
| 459 | if (token.id == Token.Id.Keyword_comptime) { | ||
| 460 | param_decl.comptime_token = token; | ||
| 461 | token = self.getNextToken(); | ||
| 462 | } else if (token.id == Token.Id.Keyword_noalias) { | ||
| 463 | param_decl.noalias_token = token; | ||
| 464 | token = self.getNextToken(); | ||
| 465 | } | ||
| 466 | if (token.id == Token.Id.Identifier) { | ||
| 467 | const next_token = self.getNextToken(); | ||
| 468 | if (next_token.id == Token.Id.Colon) { | ||
| 469 | param_decl.name_token = token; | ||
| 470 | token = self.getNextToken(); | ||
| 471 | } else { | ||
| 472 | self.putBackToken(next_token); | ||
| 473 | } | ||
| 474 | } | ||
| 475 | if (token.id == Token.Id.Ellipsis3) { | ||
| 476 | param_decl.var_args_token = token; | ||
| 477 | stack.append(State { .ExpectToken = Token.Id.RParen }) %% unreachable; | ||
| 478 | continue; | ||
| 479 | } else { | ||
| 480 | self.putBackToken(token); | ||
| 481 | } | ||
| 482 | |||
| 483 | stack.append(State { .ParamDecl = fn_proto }) %% unreachable; | ||
| 484 | %return stack.append(State.ParamDeclComma); | ||
| 485 | %return stack.append(State { | ||
| 486 | .TypeExpr = DestPtr {.Field = &param_decl.type_node} | ||
| 487 | }); | ||
| 488 | continue; | ||
| 489 | }, | ||
| 490 | |||
| 491 | State.ParamDeclComma => { | ||
| 492 | const token = self.getNextToken(); | ||
| 493 | switch (token.id) { | ||
| 494 | Token.Id.RParen => { | ||
| 495 | _ = stack.pop(); // pop off the ParamDecl | ||
| 496 | continue; | ||
| 497 | }, | ||
| 498 | Token.Id.Comma => continue, | ||
| 499 | else => return self.parseError(token, "expected ',' or ')', found {}", @tagName(token.id)), | ||
| 500 | } | ||
| 501 | }, | ||
| 502 | |||
| 503 | State.FnDef => |fn_proto| { | ||
| 504 | const token = self.getNextToken(); | ||
| 505 | switch(token.id) { | ||
| 506 | Token.Id.LBrace => { | ||
| 507 | const block = %return self.createBlock(token); | ||
| 508 | fn_proto.body_node = &block.base; | ||
| 509 | stack.append(State { .Block = block }) %% unreachable; | ||
| 510 | continue; | ||
| 511 | }, | ||
| 512 | Token.Id.Semicolon => continue, | ||
| 513 | else => return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id)), | ||
| 514 | } | ||
| 515 | }, | ||
| 516 | |||
| 517 | State.Block => |block| { | ||
| 518 | const token = self.getNextToken(); | ||
| 519 | switch (token.id) { | ||
| 520 | Token.Id.RBrace => { | ||
| 521 | block.end_token = token; | ||
| 522 | continue; | ||
| 523 | }, | ||
| 524 | else => { | ||
| 525 | self.putBackToken(token); | ||
| 526 | stack.append(State { .Block = block }) %% unreachable; | ||
| 527 | %return stack.append(State { .Statement = block }); | ||
| 528 | continue; | ||
| 529 | }, | ||
| 530 | } | ||
| 531 | }, | ||
| 532 | |||
| 533 | State.Statement => |block| { | ||
| 534 | { | ||
| 535 | // Look for comptime var, comptime const | ||
| 536 | const comptime_token = self.getNextToken(); | ||
| 537 | if (comptime_token.id == Token.Id.Keyword_comptime) { | ||
| 538 | const mut_token = self.getNextToken(); | ||
| 539 | if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) { | ||
| 540 | // TODO shouldn't need these casts | ||
| 541 | const var_decl = %return self.createAttachVarDecl(&block.statements, (?Token)(null), | ||
| 542 | mut_token, (?Token)(comptime_token), (?Token)(null)); | ||
| 543 | %return stack.append(State { .VarDecl = var_decl }); | ||
| 544 | continue; | ||
| 545 | } | ||
| 546 | self.putBackToken(mut_token); | ||
| 547 | } | ||
| 548 | self.putBackToken(comptime_token); | ||
| 549 | } | ||
| 550 | { | ||
| 551 | // Look for const, var | ||
| 552 | const mut_token = self.getNextToken(); | ||
| 553 | if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) { | ||
| 554 | // TODO shouldn't need these casts | ||
| 555 | const var_decl = %return self.createAttachVarDecl(&block.statements, (?Token)(null), | ||
| 556 | mut_token, (?Token)(null), (?Token)(null)); | ||
| 557 | %return stack.append(State { .VarDecl = var_decl }); | ||
| 558 | continue; | ||
| 559 | } | ||
| 560 | self.putBackToken(mut_token); | ||
| 561 | } | ||
| 562 | |||
| 563 | stack.append(State { .ExpectToken = Token.Id.Semicolon }) %% unreachable; | ||
| 564 | %return stack.append(State { .Expression = DestPtr{.List = &block.statements} }); | ||
| 565 | continue; | ||
| 566 | }, | ||
| 567 | |||
| 568 | // These are data, not control flow. | ||
| 569 | State.InfixOp => unreachable, | ||
| 570 | State.PrefixOp => unreachable, | ||
| 571 | State.Operand => unreachable, | ||
| 572 | } | ||
| 573 | @import("std").debug.panic("{}", @tagName(state)); | ||
| 574 | //unreachable; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | fn createRoot(self: &Parser) -> %&ast.NodeRoot { | ||
| 579 | const node = %return self.allocator.create(ast.NodeRoot); | ||
| 580 | %defer self.allocator.destroy(node); | ||
| 581 | |||
| 582 | *node = ast.NodeRoot { | ||
| 583 | .base = ast.Node {.id = ast.Node.Id.Root}, | ||
| 584 | .decls = ArrayList(&ast.Node).init(self.allocator), | ||
| 585 | }; | ||
| 586 | return node; | ||
| 587 | } | ||
| 588 | |||
| 589 | fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token, | ||
| 590 | extern_token: &const ?Token) -> %&ast.NodeVarDecl | ||
| 591 | { | ||
| 592 | const node = %return self.allocator.create(ast.NodeVarDecl); | ||
| 593 | %defer self.allocator.destroy(node); | ||
| 594 | |||
| 595 | *node = ast.NodeVarDecl { | ||
| 596 | .base = ast.Node {.id = ast.Node.Id.VarDecl}, | ||
| 597 | .visib_token = *visib_token, | ||
| 598 | .mut_token = *mut_token, | ||
| 599 | .comptime_token = *comptime_token, | ||
| 600 | .extern_token = *extern_token, | ||
| 601 | .type_node = null, | ||
| 602 | .align_node = null, | ||
| 603 | .init_node = null, | ||
| 604 | .lib_name = null, | ||
| 605 | // initialized later | ||
| 606 | .name_token = undefined, | ||
| 607 | .eq_token = undefined, | ||
| 608 | }; | ||
| 609 | return node; | ||
| 610 | } | ||
| 611 | |||
| 612 | fn createFnProto(self: &Parser, fn_token: &const Token, extern_token: &const ?Token, | ||
| 613 | cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) -> %&ast.NodeFnProto | ||
| 614 | { | ||
| 615 | const node = %return self.allocator.create(ast.NodeFnProto); | ||
| 616 | %defer self.allocator.destroy(node); | ||
| 617 | |||
| 618 | *node = ast.NodeFnProto { | ||
| 619 | .base = ast.Node {.id = ast.Node.Id.FnProto}, | ||
| 620 | .visib_token = *visib_token, | ||
| 621 | .name_token = null, | ||
| 622 | .fn_token = *fn_token, | ||
| 623 | .params = ArrayList(&ast.Node).init(self.allocator), | ||
| 624 | .return_type = null, | ||
| 625 | .var_args_token = null, | ||
| 626 | .extern_token = *extern_token, | ||
| 627 | .inline_token = *inline_token, | ||
| 628 | .cc_token = *cc_token, | ||
| 629 | .body_node = null, | ||
| 630 | .lib_name = null, | ||
| 631 | .align_expr = null, | ||
| 632 | }; | ||
| 633 | return node; | ||
| 634 | } | ||
| 635 | |||
| 636 | fn createParamDecl(self: &Parser) -> %&ast.NodeParamDecl { | ||
| 637 | const node = %return self.allocator.create(ast.NodeParamDecl); | ||
| 638 | %defer self.allocator.destroy(node); | ||
| 639 | |||
| 640 | *node = ast.NodeParamDecl { | ||
| 641 | .base = ast.Node {.id = ast.Node.Id.ParamDecl}, | ||
| 642 | .comptime_token = null, | ||
| 643 | .noalias_token = null, | ||
| 644 | .name_token = null, | ||
| 645 | .type_node = undefined, | ||
| 646 | .var_args_token = null, | ||
| 647 | }; | ||
| 648 | return node; | ||
| 649 | } | ||
| 650 | |||
| 651 | fn createBlock(self: &Parser, begin_token: &const Token) -> %&ast.NodeBlock { | ||
| 652 | const node = %return self.allocator.create(ast.NodeBlock); | ||
| 653 | %defer self.allocator.destroy(node); | ||
| 654 | |||
| 655 | *node = ast.NodeBlock { | ||
| 656 | .base = ast.Node {.id = ast.Node.Id.Block}, | ||
| 657 | .begin_token = *begin_token, | ||
| 658 | .end_token = undefined, | ||
| 659 | .statements = ArrayList(&ast.Node).init(self.allocator), | ||
| 660 | }; | ||
| 661 | return node; | ||
| 662 | } | ||
| 663 | |||
| 664 | fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) -> %&ast.NodeInfixOp { | ||
| 665 | const node = %return self.allocator.create(ast.NodeInfixOp); | ||
| 666 | %defer self.allocator.destroy(node); | ||
| 667 | |||
| 668 | *node = ast.NodeInfixOp { | ||
| 669 | .base = ast.Node {.id = ast.Node.Id.InfixOp}, | ||
| 670 | .op_token = *op_token, | ||
| 671 | .lhs = undefined, | ||
| 672 | .op = *op, | ||
| 673 | .rhs = undefined, | ||
| 674 | }; | ||
| 675 | return node; | ||
| 676 | } | ||
| 677 | |||
| 678 | fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) -> %&ast.NodePrefixOp { | ||
| 679 | const node = %return self.allocator.create(ast.NodePrefixOp); | ||
| 680 | %defer self.allocator.destroy(node); | ||
| 681 | |||
| 682 | *node = ast.NodePrefixOp { | ||
| 683 | .base = ast.Node {.id = ast.Node.Id.PrefixOp}, | ||
| 684 | .op_token = *op_token, | ||
| 685 | .op = *op, | ||
| 686 | .rhs = undefined, | ||
| 687 | }; | ||
| 688 | return node; | ||
| 689 | } | ||
| 690 | |||
| 691 | fn createIdentifier(self: &Parser, name_token: &const Token) -> %&ast.NodeIdentifier { | ||
| 692 | const node = %return self.allocator.create(ast.NodeIdentifier); | ||
| 693 | %defer self.allocator.destroy(node); | ||
| 694 | |||
| 695 | *node = ast.NodeIdentifier { | ||
| 696 | .base = ast.Node {.id = ast.Node.Id.Identifier}, | ||
| 697 | .name_token = *name_token, | ||
| 698 | }; | ||
| 699 | return node; | ||
| 700 | } | ||
| 701 | |||
| 702 | fn createIntegerLiteral(self: &Parser, token: &const Token) -> %&ast.NodeIntegerLiteral { | ||
| 703 | const node = %return self.allocator.create(ast.NodeIntegerLiteral); | ||
| 704 | %defer self.allocator.destroy(node); | ||
| 705 | |||
| 706 | *node = ast.NodeIntegerLiteral { | ||
| 707 | .base = ast.Node {.id = ast.Node.Id.IntegerLiteral}, | ||
| 708 | .token = *token, | ||
| 709 | }; | ||
| 710 | return node; | ||
| 711 | } | ||
| 712 | |||
| 713 | fn createFloatLiteral(self: &Parser, token: &const Token) -> %&ast.NodeFloatLiteral { | ||
| 714 | const node = %return self.allocator.create(ast.NodeFloatLiteral); | ||
| 715 | %defer self.allocator.destroy(node); | ||
| 716 | |||
| 717 | *node = ast.NodeFloatLiteral { | ||
| 718 | .base = ast.Node {.id = ast.Node.Id.FloatLiteral}, | ||
| 719 | .token = *token, | ||
| 720 | }; | ||
| 721 | return node; | ||
| 722 | } | ||
| 723 | |||
| 724 | fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) -> %&ast.NodeIdentifier { | ||
| 725 | const node = %return self.createIdentifier(name_token); | ||
| 726 | %defer self.allocator.destroy(node); | ||
| 727 | %return dest_ptr.store(&node.base); | ||
| 728 | return node; | ||
| 729 | } | ||
| 730 | |||
| 731 | fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) -> %&ast.NodeParamDecl { | ||
| 732 | const node = %return self.createParamDecl(); | ||
| 733 | %defer self.allocator.destroy(node); | ||
| 734 | %return list.append(&node.base); | ||
| 735 | return node; | ||
| 736 | } | ||
| 737 | |||
| 738 | fn createAttachFnProto(self: &Parser, list: &ArrayList(&ast.Node), fn_token: &const Token, | ||
| 739 | extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token, | ||
| 740 | inline_token: &const ?Token) -> %&ast.NodeFnProto | ||
| 741 | { | ||
| 742 | const node = %return self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token); | ||
| 743 | %defer self.allocator.destroy(node); | ||
| 744 | %return list.append(&node.base); | ||
| 745 | return node; | ||
| 746 | } | ||
| 747 | |||
| 748 | fn createAttachVarDecl(self: &Parser, list: &ArrayList(&ast.Node), visib_token: &const ?Token, | ||
| 749 | mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) -> %&ast.NodeVarDecl | ||
| 750 | { | ||
| 751 | const node = %return self.createVarDecl(visib_token, mut_token, comptime_token, extern_token); | ||
| 752 | %defer self.allocator.destroy(node); | ||
| 753 | %return list.append(&node.base); | ||
| 754 | return node; | ||
| 755 | } | ||
| 756 | |||
| 757 | fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) -> error { | ||
| 758 | const loc = self.tokenizer.getTokenLocation(token); | ||
| 759 | warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args); | ||
| 760 | warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]); | ||
| 761 | { | ||
| 762 | var i: usize = 0; | ||
| 763 | while (i < loc.column) : (i += 1) { | ||
| 764 | warn(" "); | ||
| 765 | } | ||
| 766 | } | ||
| 767 | { | ||
| 768 | const caret_count = token.end - token.start; | ||
| 769 | var i: usize = 0; | ||
| 770 | while (i < caret_count) : (i += 1) { | ||
| 771 | warn("~"); | ||
| 772 | } | ||
| 773 | } | ||
| 774 | warn("\n"); | ||
| 775 | return error.ParseError; | ||
| 776 | } | ||
| 777 | |||
| 778 | fn expectToken(self: &Parser, token: &const Token, id: @TagType(Token.Id)) -> %void { | ||
| 779 | if (token.id != id) { | ||
| 780 | return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id)); | ||
| 781 | } | ||
| 782 | } | ||
| 783 | |||
| 784 | fn eatToken(self: &Parser, id: @TagType(Token.Id)) -> %Token { | ||
| 785 | const token = self.getNextToken(); | ||
| 786 | %return self.expectToken(token, id); | ||
| 787 | return token; | ||
| 788 | } | ||
| 789 | |||
| 790 | fn putBackToken(self: &Parser, token: &const Token) { | ||
| 791 | self.put_back_tokens[self.put_back_count] = *token; | ||
| 792 | self.put_back_count += 1; | ||
| 793 | } | ||
| 794 | |||
| 795 | fn getNextToken(self: &Parser) -> Token { | ||
| 796 | if (self.put_back_count != 0) { | ||
| 797 | const put_back_index = self.put_back_count - 1; | ||
| 798 | const put_back_token = self.put_back_tokens[put_back_index]; | ||
| 799 | self.put_back_count = put_back_index; | ||
| 800 | return put_back_token; | ||
| 801 | } else { | ||
| 802 | return self.tokenizer.next(); | ||
| 803 | } | ||
| 804 | } | ||
| 805 | |||
| 806 | const RenderAstFrame = struct { | ||
| 807 | node: &ast.Node, | ||
| 808 | indent: usize, | ||
| 809 | }; | ||
| 810 | |||
| 811 | pub fn renderAst(self: &Parser, stream: &std.io.OutStream, root_node: &ast.NodeRoot) -> %void { | ||
| 812 | var stack = self.initUtilityArrayList(RenderAstFrame); | ||
| 813 | defer self.deinitUtilityArrayList(stack); | ||
| 814 | |||
| 815 | %return stack.append(RenderAstFrame { | ||
| 816 | .node = &root_node.base, | ||
| 817 | .indent = 0, | ||
| 818 | }); | ||
| 819 | |||
| 820 | while (stack.popOrNull()) |frame| { | ||
| 821 | { | ||
| 822 | var i: usize = 0; | ||
| 823 | while (i < frame.indent) : (i += 1) { | ||
| 824 | %return stream.print(" "); | ||
| 825 | } | ||
| 826 | } | ||
| 827 | %return stream.print("{}\n", @tagName(frame.node.id)); | ||
| 828 | var child_i: usize = 0; | ||
| 829 | while (frame.node.iterate(child_i)) |child| : (child_i += 1) { | ||
| 830 | %return stack.append(RenderAstFrame { | ||
| 831 | .node = child, | ||
| 832 | .indent = frame.indent + 2, | ||
| 833 | }); | ||
| 834 | } | ||
| 835 | } | ||
| 836 | } | ||
| 837 | |||
| 838 | const RenderState = union(enum) { | ||
| 839 | TopLevelDecl: &ast.Node, | ||
| 840 | FnProtoRParen: &ast.NodeFnProto, | ||
| 841 | ParamDecl: &ast.Node, | ||
| 842 | Text: []const u8, | ||
| 843 | Expression: &ast.Node, | ||
| 844 | VarDecl: &ast.NodeVarDecl, | ||
| 845 | Statement: &ast.Node, | ||
| 846 | PrintIndent, | ||
| 847 | Indent: usize, | ||
| 848 | }; | ||
| 849 | |||
| 850 | pub fn renderSource(self: &Parser, stream: &std.io.OutStream, root_node: &ast.NodeRoot) -> %void { | ||
| 851 | var stack = self.initUtilityArrayList(RenderState); | ||
| 852 | defer self.deinitUtilityArrayList(stack); | ||
| 853 | |||
| 854 | { | ||
| 855 | var i = root_node.decls.len; | ||
| 856 | while (i != 0) { | ||
| 857 | i -= 1; | ||
| 858 | const decl = root_node.decls.items[i]; | ||
| 859 | %return stack.append(RenderState {.TopLevelDecl = decl}); | ||
| 860 | } | ||
| 861 | } | ||
| 862 | |||
| 863 | const indent_delta = 4; | ||
| 864 | var indent: usize = 0; | ||
| 865 | while (stack.popOrNull()) |state| { | ||
| 866 | switch (state) { | ||
| 867 | RenderState.TopLevelDecl => |decl| { | ||
| 868 | switch (decl.id) { | ||
| 869 | ast.Node.Id.FnProto => { | ||
| 870 | const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", decl); | ||
| 871 | if (fn_proto.visib_token) |visib_token| { | ||
| 872 | switch (visib_token.id) { | ||
| 873 | Token.Id.Keyword_pub => %return stream.print("pub "), | ||
| 874 | Token.Id.Keyword_export => %return stream.print("export "), | ||
| 875 | else => unreachable, | ||
| 876 | } | ||
| 877 | } | ||
| 878 | if (fn_proto.extern_token) |extern_token| { | ||
| 879 | %return stream.print("{} ", self.tokenizer.getTokenSlice(extern_token)); | ||
| 880 | } | ||
| 881 | %return stream.print("fn"); | ||
| 882 | |||
| 883 | if (fn_proto.name_token) |name_token| { | ||
| 884 | %return stream.print(" {}", self.tokenizer.getTokenSlice(name_token)); | ||
| 885 | } | ||
| 886 | |||
| 887 | %return stream.print("("); | ||
| 888 | |||
| 889 | %return stack.append(RenderState { .Text = "\n" }); | ||
| 890 | if (fn_proto.body_node == null) { | ||
| 891 | %return stack.append(RenderState { .Text = ";" }); | ||
| 892 | } | ||
| 893 | |||
| 894 | %return stack.append(RenderState { .FnProtoRParen = fn_proto}); | ||
| 895 | var i = fn_proto.params.len; | ||
| 896 | while (i != 0) { | ||
| 897 | i -= 1; | ||
| 898 | const param_decl_node = fn_proto.params.items[i]; | ||
| 899 | %return stack.append(RenderState { .ParamDecl = param_decl_node}); | ||
| 900 | if (i != 0) { | ||
| 901 | %return stack.append(RenderState { .Text = ", " }); | ||
| 902 | } | ||
| 903 | } | ||
| 904 | }, | ||
| 905 | ast.Node.Id.VarDecl => { | ||
| 906 | const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl); | ||
| 907 | %return stack.append(RenderState { .Text = "\n"}); | ||
| 908 | %return stack.append(RenderState { .VarDecl = var_decl}); | ||
| 909 | |||
| 910 | }, | ||
| 911 | else => unreachable, | ||
| 912 | } | ||
| 913 | }, | ||
| 914 | |||
| 915 | RenderState.VarDecl => |var_decl| { | ||
| 916 | if (var_decl.visib_token) |visib_token| { | ||
| 917 | %return stream.print("{} ", self.tokenizer.getTokenSlice(visib_token)); | ||
| 918 | } | ||
| 919 | if (var_decl.extern_token) |extern_token| { | ||
| 920 | %return stream.print("{} ", self.tokenizer.getTokenSlice(extern_token)); | ||
| 921 | if (var_decl.lib_name != null) { | ||
| 922 | @panic("TODO"); | ||
| 923 | } | ||
| 924 | } | ||
| 925 | if (var_decl.comptime_token) |comptime_token| { | ||
| 926 | %return stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token)); | ||
| 927 | } | ||
| 928 | %return stream.print("{} ", self.tokenizer.getTokenSlice(var_decl.mut_token)); | ||
| 929 | %return stream.print("{}", self.tokenizer.getTokenSlice(var_decl.name_token)); | ||
| 930 | |||
| 931 | %return stack.append(RenderState { .Text = ";" }); | ||
| 932 | if (var_decl.init_node) |init_node| { | ||
| 933 | %return stack.append(RenderState { .Expression = init_node }); | ||
| 934 | %return stack.append(RenderState { .Text = " = " }); | ||
| 935 | } | ||
| 936 | if (var_decl.align_node) |align_node| { | ||
| 937 | %return stack.append(RenderState { .Text = ")" }); | ||
| 938 | %return stack.append(RenderState { .Expression = align_node }); | ||
| 939 | %return stack.append(RenderState { .Text = " align(" }); | ||
| 940 | } | ||
| 941 | if (var_decl.type_node) |type_node| { | ||
| 942 | %return stream.print(": "); | ||
| 943 | %return stack.append(RenderState { .Expression = type_node }); | ||
| 944 | } | ||
| 945 | }, | ||
| 946 | |||
| 947 | RenderState.ParamDecl => |base| { | ||
| 948 | const param_decl = @fieldParentPtr(ast.NodeParamDecl, "base", base); | ||
| 949 | if (param_decl.comptime_token) |comptime_token| { | ||
| 950 | %return stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token)); | ||
| 951 | } | ||
| 952 | if (param_decl.noalias_token) |noalias_token| { | ||
| 953 | %return stream.print("{} ", self.tokenizer.getTokenSlice(noalias_token)); | ||
| 954 | } | ||
| 955 | if (param_decl.name_token) |name_token| { | ||
| 956 | %return stream.print("{}: ", self.tokenizer.getTokenSlice(name_token)); | ||
| 957 | } | ||
| 958 | if (param_decl.var_args_token) |var_args_token| { | ||
| 959 | %return stream.print("{}", self.tokenizer.getTokenSlice(var_args_token)); | ||
| 960 | } else { | ||
| 961 | %return stack.append(RenderState { .Expression = param_decl.type_node}); | ||
| 962 | } | ||
| 963 | }, | ||
| 964 | RenderState.Text => |bytes| { | ||
| 965 | %return stream.write(bytes); | ||
| 966 | }, | ||
| 967 | RenderState.Expression => |base| switch (base.id) { | ||
| 968 | ast.Node.Id.Identifier => { | ||
| 969 | const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base); | ||
| 970 | %return stream.print("{}", self.tokenizer.getTokenSlice(identifier.name_token)); | ||
| 971 | }, | ||
| 972 | ast.Node.Id.Block => { | ||
| 973 | const block = @fieldParentPtr(ast.NodeBlock, "base", base); | ||
| 974 | %return stream.write("{"); | ||
| 975 | %return stack.append(RenderState { .Text = "}"}); | ||
| 976 | %return stack.append(RenderState.PrintIndent); | ||
| 977 | %return stack.append(RenderState { .Indent = indent}); | ||
| 978 | %return stack.append(RenderState { .Text = "\n"}); | ||
| 979 | var i = block.statements.len; | ||
| 980 | while (i != 0) { | ||
| 981 | i -= 1; | ||
| 982 | const statement_node = block.statements.items[i]; | ||
| 983 | %return stack.append(RenderState { .Statement = statement_node}); | ||
| 984 | %return stack.append(RenderState.PrintIndent); | ||
| 985 | %return stack.append(RenderState { .Indent = indent + indent_delta}); | ||
| 986 | %return stack.append(RenderState { .Text = "\n" }); | ||
| 987 | } | ||
| 988 | }, | ||
| 989 | ast.Node.Id.InfixOp => { | ||
| 990 | const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base); | ||
| 991 | %return stack.append(RenderState { .Expression = prefix_op_node.rhs }); | ||
| 992 | switch (prefix_op_node.op) { | ||
| 993 | ast.NodeInfixOp.InfixOp.EqualEqual => { | ||
| 994 | %return stack.append(RenderState { .Text = " == "}); | ||
| 995 | }, | ||
| 996 | ast.NodeInfixOp.InfixOp.BangEqual => { | ||
| 997 | %return stack.append(RenderState { .Text = " != "}); | ||
| 998 | }, | ||
| 999 | else => unreachable, | ||
| 1000 | } | ||
| 1001 | %return stack.append(RenderState { .Expression = prefix_op_node.lhs }); | ||
| 1002 | }, | ||
| 1003 | ast.Node.Id.PrefixOp => { | ||
| 1004 | const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base); | ||
| 1005 | %return stack.append(RenderState { .Expression = prefix_op_node.rhs }); | ||
| 1006 | switch (prefix_op_node.op) { | ||
| 1007 | ast.NodePrefixOp.PrefixOp.Return => { | ||
| 1008 | %return stream.write("return "); | ||
| 1009 | }, | ||
| 1010 | ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| { | ||
| 1011 | %return stream.write("&"); | ||
| 1012 | if (addr_of_info.volatile_token != null) { | ||
| 1013 | %return stack.append(RenderState { .Text = "volatile "}); | ||
| 1014 | } | ||
| 1015 | if (addr_of_info.const_token != null) { | ||
| 1016 | %return stack.append(RenderState { .Text = "const "}); | ||
| 1017 | } | ||
| 1018 | if (addr_of_info.align_expr) |align_expr| { | ||
| 1019 | %return stream.print("align("); | ||
| 1020 | %return stack.append(RenderState { .Text = ") "}); | ||
| 1021 | %return stack.append(RenderState { .Expression = align_expr}); | ||
| 1022 | } | ||
| 1023 | }, | ||
| 1024 | else => unreachable, | ||
| 1025 | } | ||
| 1026 | }, | ||
| 1027 | ast.Node.Id.IntegerLiteral => { | ||
| 1028 | const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base); | ||
| 1029 | %return stream.print("{}", self.tokenizer.getTokenSlice(integer_literal.token)); | ||
| 1030 | }, | ||
| 1031 | ast.Node.Id.FloatLiteral => { | ||
| 1032 | const float_literal = @fieldParentPtr(ast.NodeFloatLiteral, "base", base); | ||
| 1033 | %return stream.print("{}", self.tokenizer.getTokenSlice(float_literal.token)); | ||
| 1034 | }, | ||
| 1035 | else => unreachable, | ||
| 1036 | }, | ||
| 1037 | RenderState.FnProtoRParen => |fn_proto| { | ||
| 1038 | %return stream.print(")"); | ||
| 1039 | if (fn_proto.align_expr != null) { | ||
| 1040 | @panic("TODO"); | ||
| 1041 | } | ||
| 1042 | if (fn_proto.return_type) |return_type| { | ||
| 1043 | %return stream.print(" -> "); | ||
| 1044 | if (fn_proto.body_node) |body_node| { | ||
| 1045 | %return stack.append(RenderState { .Expression = body_node}); | ||
| 1046 | %return stack.append(RenderState { .Text = " "}); | ||
| 1047 | } | ||
| 1048 | %return stack.append(RenderState { .Expression = return_type}); | ||
| 1049 | } | ||
| 1050 | }, | ||
| 1051 | RenderState.Statement => |base| { | ||
| 1052 | switch (base.id) { | ||
| 1053 | ast.Node.Id.VarDecl => { | ||
| 1054 | const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", base); | ||
| 1055 | %return stack.append(RenderState { .VarDecl = var_decl}); | ||
| 1056 | }, | ||
| 1057 | else => { | ||
| 1058 | %return stack.append(RenderState { .Text = ";"}); | ||
| 1059 | %return stack.append(RenderState { .Expression = base}); | ||
| 1060 | }, | ||
| 1061 | } | ||
| 1062 | }, | ||
| 1063 | RenderState.Indent => |new_indent| indent = new_indent, | ||
| 1064 | RenderState.PrintIndent => %return stream.writeByteNTimes(' ', indent), | ||
| 1065 | } | ||
| 1066 | } | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | fn initUtilityArrayList(self: &Parser, comptime T: type) -> ArrayList(T) { | ||
| 1070 | const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T); | ||
| 1071 | self.utility_bytes = self.allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count); | ||
| 1072 | const typed_slice = ([]T)(self.utility_bytes); | ||
| 1073 | return ArrayList(T) { | ||
| 1074 | .allocator = self.allocator, | ||
| 1075 | .items = typed_slice, | ||
| 1076 | .len = 0, | ||
| 1077 | }; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | fn deinitUtilityArrayList(self: &Parser, list: var) { | ||
| 1081 | self.utility_bytes = ([]align(utility_bytes_align) u8)(list.items); | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | }; | ||
| 1085 | |||
| 1086 | var fixed_buffer_mem: [100 * 1024]u8 = undefined; | ||
| 1087 | |||
| 1088 | fn testParse(source: []const u8, allocator: &mem.Allocator) -> %[]u8 { | ||
| 1089 | var tokenizer = Tokenizer.init(source); | ||
| 1090 | var parser = Parser.init(&tokenizer, allocator, "(memory buffer)"); | ||
| 1091 | defer parser.deinit(); | ||
| 1092 | |||
| 1093 | const root_node = %return parser.parse(); | ||
| 1094 | defer parser.freeAst(root_node); | ||
| 1095 | |||
| 1096 | var buffer = %return std.Buffer.initSize(allocator, 0); | ||
| 1097 | var buffer_out_stream = io.BufferOutStream.init(&buffer); | ||
| 1098 | %return parser.renderSource(&buffer_out_stream.stream, root_node); | ||
| 1099 | return buffer.toOwnedSlice(); | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | // TODO test for memory leaks | ||
| 1103 | // TODO test for valid frees | ||
| 1104 | fn testCanonical(source: []const u8) { | ||
| 1105 | const needed_alloc_count = x: { | ||
| 1106 | // Try it once with unlimited memory, make sure it works | ||
| 1107 | var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]); | ||
| 1108 | var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize)); | ||
| 1109 | const result_source = testParse(source, &failing_allocator.allocator) %% @panic("test failed"); | ||
| 1110 | if (!mem.eql(u8, result_source, source)) { | ||
| 1111 | warn("\n====== expected this output: =========\n"); | ||
| 1112 | warn("{}", source); | ||
| 1113 | warn("\n======== instead found this: =========\n"); | ||
| 1114 | warn("{}", result_source); | ||
| 1115 | warn("\n======================================\n"); | ||
| 1116 | @panic("test failed"); | ||
| 1117 | } | ||
| 1118 | failing_allocator.allocator.free(result_source); | ||
| 1119 | break :x failing_allocator.index; | ||
| 1120 | }; | ||
| 1121 | |||
| 1122 | // TODO make this pass | ||
| 1123 | //var fail_index = needed_alloc_count; | ||
| 1124 | //while (fail_index != 0) { | ||
| 1125 | // fail_index -= 1; | ||
| 1126 | // var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]); | ||
| 1127 | // var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); | ||
| 1128 | // if (testParse(source, &failing_allocator.allocator)) |_| { | ||
| 1129 | // @panic("non-deterministic memory usage"); | ||
| 1130 | // } else |err| { | ||
| 1131 | // assert(err == error.OutOfMemory); | ||
| 1132 | // } | ||
| 1133 | //} | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | test "zig fmt" { | ||
| 1137 | if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) { | ||
| 1138 | // TODO get this test passing | ||
| 1139 | // https://github.com/zig-lang/zig/issues/537 | ||
| 1140 | return; | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | testCanonical( | ||
| 1144 | \\extern fn puts(s: &const u8) -> c_int; | ||
| 1145 | \\ | ||
| 1146 | ); | ||
| 1147 | |||
| 1148 | testCanonical( | ||
| 1149 | \\const a = b; | ||
| 1150 | \\pub const a = b; | ||
| 1151 | \\var a = b; | ||
| 1152 | \\pub var a = b; | ||
| 1153 | \\const a: i32 = b; | ||
| 1154 | \\pub const a: i32 = b; | ||
| 1155 | \\var a: i32 = b; | ||
| 1156 | \\pub var a: i32 = b; | ||
| 1157 | \\ | ||
| 1158 | ); | ||
| 1159 | |||
| 1160 | testCanonical( | ||
| 1161 | \\extern var foo: c_int; | ||
| 1162 | \\ | ||
| 1163 | ); | ||
| 1164 | |||
| 1165 | testCanonical( | ||
| 1166 | \\var foo: c_int align(1); | ||
| 1167 | \\ | ||
| 1168 | ); | ||
| 1169 | |||
| 1170 | testCanonical( | ||
| 1171 | \\fn main(argc: c_int, argv: &&u8) -> c_int { | ||
| 1172 | \\ const a = b; | ||
| 1173 | \\} | ||
| 1174 | \\ | ||
| 1175 | ); | ||
| 1176 | |||
| 1177 | testCanonical( | ||
| 1178 | \\fn foo(argc: c_int, argv: &&u8) -> c_int { | ||
| 1179 | \\ return 0; | ||
| 1180 | \\} | ||
| 1181 | \\ | ||
| 1182 | ); | ||
| 1183 | |||
| 1184 | testCanonical( | ||
| 1185 | \\extern fn f1(s: &align(&u8) u8) -> c_int; | ||
| 1186 | \\ | ||
| 1187 | ); | ||
| 1188 | |||
| 1189 | testCanonical( | ||
| 1190 | \\extern fn f1(s: &&align(1) &const &volatile u8) -> c_int; | ||
| 1191 | \\extern fn f2(s: &align(1) const &align(1) volatile &const volatile u8) -> c_int; | ||
| 1192 | \\extern fn f3(s: &align(1) const volatile u8) -> c_int; | ||
| 1193 | \\ | ||
| 1194 | ); | ||
| 1195 | |||
| 1196 | testCanonical( | ||
| 1197 | \\fn f1(a: bool, b: bool) -> bool { | ||
| 1198 | \\ a != b; | ||
| 1199 | \\ return a == b; | ||
| 1200 | \\} | ||
| 1201 | \\ | ||
| 1202 | ); | ||
| 1203 | } | ||
src-self-hosted/target.zig created+60| ... | @@ -0,0 +1,60 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const c = @import("c.zig"); | ||
| 3 | |||
| 4 | pub const CrossTarget = struct { | ||
| 5 | arch: builtin.Arch, | ||
| 6 | os: builtin.Os, | ||
| 7 | environ: builtin.Environ, | ||
| 8 | }; | ||
| 9 | |||
| 10 | pub const Target = union(enum) { | ||
| 11 | Native, | ||
| 12 | Cross: CrossTarget, | ||
| 13 | |||
| 14 | pub fn oFileExt(self: &const Target) -> []const u8 { | ||
| 15 | const environ = switch (*self) { | ||
| 16 | Target.Native => builtin.environ, | ||
| 17 | Target.Cross => |t| t.environ, | ||
| 18 | }; | ||
| 19 | return switch (environ) { | ||
| 20 | builtin.Environ.msvc => ".obj", | ||
| 21 | else => ".o", | ||
| 22 | }; | ||
| 23 | } | ||
| 24 | |||
| 25 | pub fn exeFileExt(self: &const Target) -> []const u8 { | ||
| 26 | return switch (self.getOs()) { | ||
| 27 | builtin.Os.windows => ".exe", | ||
| 28 | else => "", | ||
| 29 | }; | ||
| 30 | } | ||
| 31 | |||
| 32 | pub fn getOs(self: &const Target) -> builtin.Os { | ||
| 33 | return switch (*self) { | ||
| 34 | Target.Native => builtin.os, | ||
| 35 | Target.Cross => |t| t.os, | ||
| 36 | }; | ||
| 37 | } | ||
| 38 | |||
| 39 | pub fn isDarwin(self: &const Target) -> bool { | ||
| 40 | return switch (self.getOs()) { | ||
| 41 | builtin.Os.darwin, builtin.Os.ios, builtin.Os.macosx => true, | ||
| 42 | else => false, | ||
| 43 | }; | ||
| 44 | } | ||
| 45 | |||
| 46 | pub fn isWindows(self: &const Target) -> bool { | ||
| 47 | return switch (self.getOs()) { | ||
| 48 | builtin.Os.windows => true, | ||
| 49 | else => false, | ||
| 50 | }; | ||
| 51 | } | ||
| 52 | }; | ||
| 53 | |||
| 54 | pub fn initializeAll() { | ||
| 55 | c.LLVMInitializeAllTargets(); | ||
| 56 | c.LLVMInitializeAllTargetInfos(); | ||
| 57 | c.LLVMInitializeAllTargetMCs(); | ||
| 58 | c.LLVMInitializeAllAsmPrinters(); | ||
| 59 | c.LLVMInitializeAllAsmParsers(); | ||
| 60 | } | ||
src-self-hosted/tokenizer.zig created+509| ... | @@ -0,0 +1,509 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | |||
| 4 | pub const Token = struct { | ||
| 5 | id: Id, | ||
| 6 | start: usize, | ||
| 7 | end: usize, | ||
| 8 | |||
| 9 | const KeywordId = struct { | ||
| 10 | bytes: []const u8, | ||
| 11 | id: Id, | ||
| 12 | }; | ||
| 13 | |||
| 14 | const keywords = []KeywordId { | ||
| 15 | KeywordId{.bytes="align", .id = Id.Keyword_align}, | ||
| 16 | KeywordId{.bytes="and", .id = Id.Keyword_and}, | ||
| 17 | KeywordId{.bytes="asm", .id = Id.Keyword_asm}, | ||
| 18 | KeywordId{.bytes="break", .id = Id.Keyword_break}, | ||
| 19 | KeywordId{.bytes="coldcc", .id = Id.Keyword_coldcc}, | ||
| 20 | KeywordId{.bytes="comptime", .id = Id.Keyword_comptime}, | ||
| 21 | KeywordId{.bytes="const", .id = Id.Keyword_const}, | ||
| 22 | KeywordId{.bytes="continue", .id = Id.Keyword_continue}, | ||
| 23 | KeywordId{.bytes="defer", .id = Id.Keyword_defer}, | ||
| 24 | KeywordId{.bytes="else", .id = Id.Keyword_else}, | ||
| 25 | KeywordId{.bytes="enum", .id = Id.Keyword_enum}, | ||
| 26 | KeywordId{.bytes="error", .id = Id.Keyword_error}, | ||
| 27 | KeywordId{.bytes="export", .id = Id.Keyword_export}, | ||
| 28 | KeywordId{.bytes="extern", .id = Id.Keyword_extern}, | ||
| 29 | KeywordId{.bytes="false", .id = Id.Keyword_false}, | ||
| 30 | KeywordId{.bytes="fn", .id = Id.Keyword_fn}, | ||
| 31 | KeywordId{.bytes="for", .id = Id.Keyword_for}, | ||
| 32 | KeywordId{.bytes="goto", .id = Id.Keyword_goto}, | ||
| 33 | KeywordId{.bytes="if", .id = Id.Keyword_if}, | ||
| 34 | KeywordId{.bytes="inline", .id = Id.Keyword_inline}, | ||
| 35 | KeywordId{.bytes="nakedcc", .id = Id.Keyword_nakedcc}, | ||
| 36 | KeywordId{.bytes="noalias", .id = Id.Keyword_noalias}, | ||
| 37 | KeywordId{.bytes="null", .id = Id.Keyword_null}, | ||
| 38 | KeywordId{.bytes="or", .id = Id.Keyword_or}, | ||
| 39 | KeywordId{.bytes="packed", .id = Id.Keyword_packed}, | ||
| 40 | KeywordId{.bytes="pub", .id = Id.Keyword_pub}, | ||
| 41 | KeywordId{.bytes="return", .id = Id.Keyword_return}, | ||
| 42 | KeywordId{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc}, | ||
| 43 | KeywordId{.bytes="struct", .id = Id.Keyword_struct}, | ||
| 44 | KeywordId{.bytes="switch", .id = Id.Keyword_switch}, | ||
| 45 | KeywordId{.bytes="test", .id = Id.Keyword_test}, | ||
| 46 | KeywordId{.bytes="this", .id = Id.Keyword_this}, | ||
| 47 | KeywordId{.bytes="true", .id = Id.Keyword_true}, | ||
| 48 | KeywordId{.bytes="undefined", .id = Id.Keyword_undefined}, | ||
| 49 | KeywordId{.bytes="union", .id = Id.Keyword_union}, | ||
| 50 | KeywordId{.bytes="unreachable", .id = Id.Keyword_unreachable}, | ||
| 51 | KeywordId{.bytes="use", .id = Id.Keyword_use}, | ||
| 52 | KeywordId{.bytes="var", .id = Id.Keyword_var}, | ||
| 53 | KeywordId{.bytes="volatile", .id = Id.Keyword_volatile}, | ||
| 54 | KeywordId{.bytes="while", .id = Id.Keyword_while}, | ||
| 55 | }; | ||
| 56 | |||
| 57 | fn getKeyword(bytes: []const u8) -> ?Id { | ||
| 58 | for (keywords) |kw| { | ||
| 59 | if (mem.eql(u8, kw.bytes, bytes)) { | ||
| 60 | return kw.id; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | return null; | ||
| 64 | } | ||
| 65 | |||
| 66 | const StrLitKind = enum {Normal, C}; | ||
| 67 | |||
| 68 | pub const Id = union(enum) { | ||
| 69 | Invalid, | ||
| 70 | Identifier, | ||
| 71 | StringLiteral: StrLitKind, | ||
| 72 | Eof, | ||
| 73 | Builtin, | ||
| 74 | Bang, | ||
| 75 | Equal, | ||
| 76 | EqualEqual, | ||
| 77 | BangEqual, | ||
| 78 | LParen, | ||
| 79 | RParen, | ||
| 80 | Semicolon, | ||
| 81 | Percent, | ||
| 82 | LBrace, | ||
| 83 | RBrace, | ||
| 84 | Period, | ||
| 85 | Ellipsis2, | ||
| 86 | Ellipsis3, | ||
| 87 | Minus, | ||
| 88 | Arrow, | ||
| 89 | Colon, | ||
| 90 | Slash, | ||
| 91 | Comma, | ||
| 92 | Ampersand, | ||
| 93 | AmpersandEqual, | ||
| 94 | IntegerLiteral, | ||
| 95 | FloatLiteral, | ||
| 96 | Keyword_align, | ||
| 97 | Keyword_and, | ||
| 98 | Keyword_asm, | ||
| 99 | Keyword_break, | ||
| 100 | Keyword_coldcc, | ||
| 101 | Keyword_comptime, | ||
| 102 | Keyword_const, | ||
| 103 | Keyword_continue, | ||
| 104 | Keyword_defer, | ||
| 105 | Keyword_else, | ||
| 106 | Keyword_enum, | ||
| 107 | Keyword_error, | ||
| 108 | Keyword_export, | ||
| 109 | Keyword_extern, | ||
| 110 | Keyword_false, | ||
| 111 | Keyword_fn, | ||
| 112 | Keyword_for, | ||
| 113 | Keyword_goto, | ||
| 114 | Keyword_if, | ||
| 115 | Keyword_inline, | ||
| 116 | Keyword_nakedcc, | ||
| 117 | Keyword_noalias, | ||
| 118 | Keyword_null, | ||
| 119 | Keyword_or, | ||
| 120 | Keyword_packed, | ||
| 121 | Keyword_pub, | ||
| 122 | Keyword_return, | ||
| 123 | Keyword_stdcallcc, | ||
| 124 | Keyword_struct, | ||
| 125 | Keyword_switch, | ||
| 126 | Keyword_test, | ||
| 127 | Keyword_this, | ||
| 128 | Keyword_true, | ||
| 129 | Keyword_undefined, | ||
| 130 | Keyword_union, | ||
| 131 | Keyword_unreachable, | ||
| 132 | Keyword_use, | ||
| 133 | Keyword_var, | ||
| 134 | Keyword_volatile, | ||
| 135 | Keyword_while, | ||
| 136 | }; | ||
| 137 | }; | ||
| 138 | |||
| 139 | pub const Tokenizer = struct { | ||
| 140 | buffer: []const u8, | ||
| 141 | index: usize, | ||
| 142 | |||
| 143 | pub const Location = struct { | ||
| 144 | line: usize, | ||
| 145 | column: usize, | ||
| 146 | line_start: usize, | ||
| 147 | line_end: usize, | ||
| 148 | }; | ||
| 149 | |||
| 150 | pub fn getTokenLocation(self: &Tokenizer, token: &const Token) -> Location { | ||
| 151 | var loc = Location { | ||
| 152 | .line = 0, | ||
| 153 | .column = 0, | ||
| 154 | .line_start = 0, | ||
| 155 | .line_end = 0, | ||
| 156 | }; | ||
| 157 | for (self.buffer) |c, i| { | ||
| 158 | if (i == token.start) { | ||
| 159 | loc.line_end = i; | ||
| 160 | while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {} | ||
| 161 | return loc; | ||
| 162 | } | ||
| 163 | if (c == '\n') { | ||
| 164 | loc.line += 1; | ||
| 165 | loc.column = 0; | ||
| 166 | loc.line_start = i + 1; | ||
| 167 | } else { | ||
| 168 | loc.column += 1; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | return loc; | ||
| 172 | } | ||
| 173 | |||
| 174 | /// For debugging purposes | ||
| 175 | pub fn dump(self: &Tokenizer, token: &const Token) { | ||
| 176 | std.debug.warn("{} \"{}\"\n", @tagName(token.id), self.buffer[token.start..token.end]); | ||
| 177 | } | ||
| 178 | |||
| 179 | pub fn init(buffer: []const u8) -> Tokenizer { | ||
| 180 | return Tokenizer { | ||
| 181 | .buffer = buffer, | ||
| 182 | .index = 0, | ||
| 183 | }; | ||
| 184 | } | ||
| 185 | |||
| 186 | const State = enum { | ||
| 187 | Start, | ||
| 188 | Identifier, | ||
| 189 | Builtin, | ||
| 190 | C, | ||
| 191 | StringLiteral, | ||
| 192 | StringLiteralBackslash, | ||
| 193 | Equal, | ||
| 194 | Bang, | ||
| 195 | Minus, | ||
| 196 | Slash, | ||
| 197 | LineComment, | ||
| 198 | Zero, | ||
| 199 | IntegerLiteral, | ||
| 200 | NumberDot, | ||
| 201 | FloatFraction, | ||
| 202 | FloatExponentUnsigned, | ||
| 203 | FloatExponentNumber, | ||
| 204 | Ampersand, | ||
| 205 | Period, | ||
| 206 | Period2, | ||
| 207 | }; | ||
| 208 | |||
| 209 | pub fn next(self: &Tokenizer) -> Token { | ||
| 210 | var state = State.Start; | ||
| 211 | var result = Token { | ||
| 212 | .id = Token.Id.Eof, | ||
| 213 | .start = self.index, | ||
| 214 | .end = undefined, | ||
| 215 | }; | ||
| 216 | while (self.index < self.buffer.len) : (self.index += 1) { | ||
| 217 | const c = self.buffer[self.index]; | ||
| 218 | switch (state) { | ||
| 219 | State.Start => switch (c) { | ||
| 220 | ' ', '\n' => { | ||
| 221 | result.start = self.index + 1; | ||
| 222 | }, | ||
| 223 | 'c' => { | ||
| 224 | state = State.C; | ||
| 225 | result.id = Token.Id.Identifier; | ||
| 226 | }, | ||
| 227 | '"' => { | ||
| 228 | state = State.StringLiteral; | ||
| 229 | result.id = Token.Id { .StringLiteral = Token.StrLitKind.Normal }; | ||
| 230 | }, | ||
| 231 | 'a'...'b', 'd'...'z', 'A'...'Z', '_' => { | ||
| 232 | state = State.Identifier; | ||
| 233 | result.id = Token.Id.Identifier; | ||
| 234 | }, | ||
| 235 | '@' => { | ||
| 236 | state = State.Builtin; | ||
| 237 | result.id = Token.Id.Builtin; | ||
| 238 | }, | ||
| 239 | '=' => { | ||
| 240 | state = State.Equal; | ||
| 241 | }, | ||
| 242 | '!' => { | ||
| 243 | state = State.Bang; | ||
| 244 | }, | ||
| 245 | '(' => { | ||
| 246 | result.id = Token.Id.LParen; | ||
| 247 | self.index += 1; | ||
| 248 | break; | ||
| 249 | }, | ||
| 250 | ')' => { | ||
| 251 | result.id = Token.Id.RParen; | ||
| 252 | self.index += 1; | ||
| 253 | break; | ||
| 254 | }, | ||
| 255 | ';' => { | ||
| 256 | result.id = Token.Id.Semicolon; | ||
| 257 | self.index += 1; | ||
| 258 | break; | ||
| 259 | }, | ||
| 260 | ',' => { | ||
| 261 | result.id = Token.Id.Comma; | ||
| 262 | self.index += 1; | ||
| 263 | break; | ||
| 264 | }, | ||
| 265 | ':' => { | ||
| 266 | result.id = Token.Id.Colon; | ||
| 267 | self.index += 1; | ||
| 268 | break; | ||
| 269 | }, | ||
| 270 | '%' => { | ||
| 271 | result.id = Token.Id.Percent; | ||
| 272 | self.index += 1; | ||
| 273 | break; | ||
| 274 | }, | ||
| 275 | '{' => { | ||
| 276 | result.id = Token.Id.LBrace; | ||
| 277 | self.index += 1; | ||
| 278 | break; | ||
| 279 | }, | ||
| 280 | '}' => { | ||
| 281 | result.id = Token.Id.RBrace; | ||
| 282 | self.index += 1; | ||
| 283 | break; | ||
| 284 | }, | ||
| 285 | '.' => { | ||
| 286 | state = State.Period; | ||
| 287 | }, | ||
| 288 | '-' => { | ||
| 289 | state = State.Minus; | ||
| 290 | }, | ||
| 291 | '/' => { | ||
| 292 | state = State.Slash; | ||
| 293 | }, | ||
| 294 | '&' => { | ||
| 295 | state = State.Ampersand; | ||
| 296 | }, | ||
| 297 | '0' => { | ||
| 298 | state = State.Zero; | ||
| 299 | result.id = Token.Id.IntegerLiteral; | ||
| 300 | }, | ||
| 301 | '1'...'9' => { | ||
| 302 | state = State.IntegerLiteral; | ||
| 303 | result.id = Token.Id.IntegerLiteral; | ||
| 304 | }, | ||
| 305 | else => { | ||
| 306 | result.id = Token.Id.Invalid; | ||
| 307 | self.index += 1; | ||
| 308 | break; | ||
| 309 | }, | ||
| 310 | }, | ||
| 311 | State.Ampersand => switch (c) { | ||
| 312 | '=' => { | ||
| 313 | result.id = Token.Id.AmpersandEqual; | ||
| 314 | self.index += 1; | ||
| 315 | break; | ||
| 316 | }, | ||
| 317 | else => { | ||
| 318 | result.id = Token.Id.Ampersand; | ||
| 319 | break; | ||
| 320 | }, | ||
| 321 | }, | ||
| 322 | State.Identifier => switch (c) { | ||
| 323 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, | ||
| 324 | else => { | ||
| 325 | if (Token.getKeyword(self.buffer[result.start..self.index])) |id| { | ||
| 326 | result.id = id; | ||
| 327 | } | ||
| 328 | break; | ||
| 329 | }, | ||
| 330 | }, | ||
| 331 | State.Builtin => switch (c) { | ||
| 332 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, | ||
| 333 | else => break, | ||
| 334 | }, | ||
| 335 | State.C => switch (c) { | ||
| 336 | '\\' => @panic("TODO"), | ||
| 337 | '"' => { | ||
| 338 | state = State.StringLiteral; | ||
| 339 | result.id = Token.Id { .StringLiteral = Token.StrLitKind.C }; | ||
| 340 | }, | ||
| 341 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => { | ||
| 342 | state = State.Identifier; | ||
| 343 | }, | ||
| 344 | else => break, | ||
| 345 | }, | ||
| 346 | State.StringLiteral => switch (c) { | ||
| 347 | '\\' => { | ||
| 348 | state = State.StringLiteralBackslash; | ||
| 349 | }, | ||
| 350 | '"' => { | ||
| 351 | self.index += 1; | ||
| 352 | break; | ||
| 353 | }, | ||
| 354 | '\n' => break, // Look for this error later. | ||
| 355 | else => {}, | ||
| 356 | }, | ||
| 357 | |||
| 358 | State.StringLiteralBackslash => switch (c) { | ||
| 359 | '\n' => break, // Look for this error later. | ||
| 360 | else => { | ||
| 361 | state = State.StringLiteral; | ||
| 362 | }, | ||
| 363 | }, | ||
| 364 | |||
| 365 | State.Bang => switch (c) { | ||
| 366 | '=' => { | ||
| 367 | result.id = Token.Id.BangEqual; | ||
| 368 | self.index += 1; | ||
| 369 | break; | ||
| 370 | }, | ||
| 371 | else => { | ||
| 372 | result.id = Token.Id.Bang; | ||
| 373 | break; | ||
| 374 | }, | ||
| 375 | }, | ||
| 376 | |||
| 377 | State.Equal => switch (c) { | ||
| 378 | '=' => { | ||
| 379 | result.id = Token.Id.EqualEqual; | ||
| 380 | self.index += 1; | ||
| 381 | break; | ||
| 382 | }, | ||
| 383 | else => { | ||
| 384 | result.id = Token.Id.Equal; | ||
| 385 | break; | ||
| 386 | }, | ||
| 387 | }, | ||
| 388 | |||
| 389 | State.Minus => switch (c) { | ||
| 390 | '>' => { | ||
| 391 | result.id = Token.Id.Arrow; | ||
| 392 | self.index += 1; | ||
| 393 | break; | ||
| 394 | }, | ||
| 395 | else => { | ||
| 396 | result.id = Token.Id.Minus; | ||
| 397 | break; | ||
| 398 | }, | ||
| 399 | }, | ||
| 400 | |||
| 401 | State.Period => switch (c) { | ||
| 402 | '.' => { | ||
| 403 | state = State.Period2; | ||
| 404 | }, | ||
| 405 | else => { | ||
| 406 | result.id = Token.Id.Period; | ||
| 407 | break; | ||
| 408 | }, | ||
| 409 | }, | ||
| 410 | |||
| 411 | State.Period2 => switch (c) { | ||
| 412 | '.' => { | ||
| 413 | result.id = Token.Id.Ellipsis3; | ||
| 414 | self.index += 1; | ||
| 415 | break; | ||
| 416 | }, | ||
| 417 | else => { | ||
| 418 | result.id = Token.Id.Ellipsis2; | ||
| 419 | break; | ||
| 420 | }, | ||
| 421 | }, | ||
| 422 | |||
| 423 | State.Slash => switch (c) { | ||
| 424 | '/' => { | ||
| 425 | result.id = undefined; | ||
| 426 | state = State.LineComment; | ||
| 427 | }, | ||
| 428 | else => { | ||
| 429 | result.id = Token.Id.Slash; | ||
| 430 | break; | ||
| 431 | }, | ||
| 432 | }, | ||
| 433 | State.LineComment => switch (c) { | ||
| 434 | '\n' => { | ||
| 435 | state = State.Start; | ||
| 436 | result = Token { | ||
| 437 | .id = Token.Id.Eof, | ||
| 438 | .start = self.index + 1, | ||
| 439 | .end = undefined, | ||
| 440 | }; | ||
| 441 | }, | ||
| 442 | else => {}, | ||
| 443 | }, | ||
| 444 | State.Zero => switch (c) { | ||
| 445 | 'b', 'o', 'x' => { | ||
| 446 | state = State.IntegerLiteral; | ||
| 447 | }, | ||
| 448 | else => { | ||
| 449 | // reinterpret as a normal number | ||
| 450 | self.index -= 1; | ||
| 451 | state = State.IntegerLiteral; | ||
| 452 | }, | ||
| 453 | }, | ||
| 454 | State.IntegerLiteral => switch (c) { | ||
| 455 | '.' => { | ||
| 456 | state = State.NumberDot; | ||
| 457 | }, | ||
| 458 | 'p', 'P', 'e', 'E' => { | ||
| 459 | state = State.FloatExponentUnsigned; | ||
| 460 | }, | ||
| 461 | '0'...'9', 'a'...'f', 'A'...'F' => {}, | ||
| 462 | else => break, | ||
| 463 | }, | ||
| 464 | State.NumberDot => switch (c) { | ||
| 465 | '.' => { | ||
| 466 | self.index -= 1; | ||
| 467 | state = State.Start; | ||
| 468 | break; | ||
| 469 | }, | ||
| 470 | else => { | ||
| 471 | self.index -= 1; | ||
| 472 | result.id = Token.Id.FloatLiteral; | ||
| 473 | state = State.FloatFraction; | ||
| 474 | }, | ||
| 475 | }, | ||
| 476 | State.FloatFraction => switch (c) { | ||
| 477 | 'p', 'P', 'e', 'E' => { | ||
| 478 | state = State.FloatExponentUnsigned; | ||
| 479 | }, | ||
| 480 | '0'...'9', 'a'...'f', 'A'...'F' => {}, | ||
| 481 | else => break, | ||
| 482 | }, | ||
| 483 | State.FloatExponentUnsigned => switch (c) { | ||
| 484 | '+', '-' => { | ||
| 485 | state = State.FloatExponentNumber; | ||
| 486 | }, | ||
| 487 | else => { | ||
| 488 | // reinterpret as a normal exponent number | ||
| 489 | self.index -= 1; | ||
| 490 | state = State.FloatExponentNumber; | ||
| 491 | } | ||
| 492 | }, | ||
| 493 | State.FloatExponentNumber => switch (c) { | ||
| 494 | '0'...'9', 'a'...'f', 'A'...'F' => {}, | ||
| 495 | else => break, | ||
| 496 | }, | ||
| 497 | } | ||
| 498 | } | ||
| 499 | result.end = self.index; | ||
| 500 | // TODO check state when returning EOF | ||
| 501 | return result; | ||
| 502 | } | ||
| 503 | |||
| 504 | pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) -> []const u8 { | ||
| 505 | return self.buffer[token.start..token.end]; | ||
| 506 | } | ||
| 507 | }; | ||
| 508 | |||
| 509 | |||
src/all_types.hpp+44-49| ... | @@ -26,7 +26,6 @@ struct ScopeFnDef; | ... | @@ -26,7 +26,6 @@ struct ScopeFnDef; |
| 26 | struct TypeTableEntry; | 26 | struct TypeTableEntry; |
| 27 | struct VariableTableEntry; | 27 | struct VariableTableEntry; |
| 28 | struct ErrorTableEntry; | 28 | struct ErrorTableEntry; |
| 29 | struct LabelTableEntry; | ||
| 30 | struct BuiltinFnEntry; | 29 | struct BuiltinFnEntry; |
| 31 | struct TypeStructField; | 30 | struct TypeStructField; |
| 32 | struct CodeGen; | 31 | struct CodeGen; |
| ... | @@ -37,6 +36,7 @@ struct IrBasicBlock; | ... | @@ -37,6 +36,7 @@ struct IrBasicBlock; |
| 37 | struct ScopeDecls; | 36 | struct ScopeDecls; |
| 38 | struct ZigWindowsSDK; | 37 | struct ZigWindowsSDK; |
| 39 | struct Tld; | 38 | struct Tld; |
| 39 | struct TldExport; | ||
| 40 | 40 | ||
| 41 | struct IrGotoItem { | 41 | struct IrGotoItem { |
| 42 | AstNode *source_node; | 42 | AstNode *source_node; |
| ... | @@ -53,7 +53,6 @@ struct IrExecutable { | ... | @@ -53,7 +53,6 @@ struct IrExecutable { |
| 53 | size_t *backward_branch_count; | 53 | size_t *backward_branch_count; |
| 54 | size_t backward_branch_quota; | 54 | size_t backward_branch_quota; |
| 55 | bool invalid; | 55 | bool invalid; |
| 56 | ZigList<LabelTableEntry *> all_labels; | ||
| 57 | ZigList<IrGotoItem> goto_list; | 56 | ZigList<IrGotoItem> goto_list; |
| 58 | bool is_inline; | 57 | bool is_inline; |
| 59 | FnTableEntry *fn_entry; | 58 | FnTableEntry *fn_entry; |
| ... | @@ -272,7 +271,6 @@ enum ReturnKnowledge { | ... | @@ -272,7 +271,6 @@ enum ReturnKnowledge { |
| 272 | enum VisibMod { | 271 | enum VisibMod { |
| 273 | VisibModPrivate, | 272 | VisibModPrivate, |
| 274 | VisibModPub, | 273 | VisibModPub, |
| 275 | VisibModExport, | ||
| 276 | }; | 274 | }; |
| 277 | 275 | ||
| 278 | enum GlobalLinkageId { | 276 | enum GlobalLinkageId { |
| ... | @@ -313,11 +311,8 @@ struct TldVar { | ... | @@ -313,11 +311,8 @@ struct TldVar { |
| 313 | Tld base; | 311 | Tld base; |
| 314 | 312 | ||
| 315 | VariableTableEntry *var; | 313 | VariableTableEntry *var; |
| 316 | AstNode *set_global_section_node; | ||
| 317 | Buf *section_name; | ||
| 318 | AstNode *set_global_linkage_node; | ||
| 319 | GlobalLinkageId linkage; | ||
| 320 | Buf *extern_lib_name; | 314 | Buf *extern_lib_name; |
| 315 | Buf *section_name; | ||
| 321 | }; | 316 | }; |
| 322 | 317 | ||
| 323 | struct TldFn { | 318 | struct TldFn { |
| ... | @@ -389,8 +384,6 @@ enum NodeType { | ... | @@ -389,8 +384,6 @@ enum NodeType { |
| 389 | NodeTypeSwitchExpr, | 384 | NodeTypeSwitchExpr, |
| 390 | NodeTypeSwitchProng, | 385 | NodeTypeSwitchProng, |
| 391 | NodeTypeSwitchRange, | 386 | NodeTypeSwitchRange, |
| 392 | NodeTypeLabel, | ||
| 393 | NodeTypeGoto, | ||
| 394 | NodeTypeCompTime, | 387 | NodeTypeCompTime, |
| 395 | NodeTypeBreak, | 388 | NodeTypeBreak, |
| 396 | NodeTypeContinue, | 389 | NodeTypeContinue, |
| ... | @@ -425,6 +418,7 @@ struct AstNodeFnProto { | ... | @@ -425,6 +418,7 @@ struct AstNodeFnProto { |
| 425 | AstNode *return_type; | 418 | AstNode *return_type; |
| 426 | bool is_var_args; | 419 | bool is_var_args; |
| 427 | bool is_extern; | 420 | bool is_extern; |
| 421 | bool is_export; | ||
| 428 | bool is_inline; | 422 | bool is_inline; |
| 429 | CallingConvention cc; | 423 | CallingConvention cc; |
| 430 | AstNode *fn_def_node; | 424 | AstNode *fn_def_node; |
| ... | @@ -432,6 +426,8 @@ struct AstNodeFnProto { | ... | @@ -432,6 +426,8 @@ struct AstNodeFnProto { |
| 432 | Buf *lib_name; | 426 | Buf *lib_name; |
| 433 | // populated if the "align A" is present | 427 | // populated if the "align A" is present |
| 434 | AstNode *align_expr; | 428 | AstNode *align_expr; |
| 429 | // populated if the "section(S)" is present | ||
| 430 | AstNode *section_expr; | ||
| 435 | }; | 431 | }; |
| 436 | 432 | ||
| 437 | struct AstNodeFnDef { | 433 | struct AstNodeFnDef { |
| ... | @@ -452,8 +448,8 @@ struct AstNodeParamDecl { | ... | @@ -452,8 +448,8 @@ struct AstNodeParamDecl { |
| 452 | }; | 448 | }; |
| 453 | 449 | ||
| 454 | struct AstNodeBlock { | 450 | struct AstNodeBlock { |
| 451 | Buf *name; | ||
| 455 | ZigList<AstNode *> statements; | 452 | ZigList<AstNode *> statements; |
| 456 | bool last_statement_is_result_expression; | ||
| 457 | }; | 453 | }; |
| 458 | 454 | ||
| 459 | enum ReturnKind { | 455 | enum ReturnKind { |
| ... | @@ -480,15 +476,18 @@ struct AstNodeVariableDeclaration { | ... | @@ -480,15 +476,18 @@ struct AstNodeVariableDeclaration { |
| 480 | VisibMod visib_mod; | 476 | VisibMod visib_mod; |
| 481 | Buf *symbol; | 477 | Buf *symbol; |
| 482 | bool is_const; | 478 | bool is_const; |
| 483 | bool is_inline; | 479 | bool is_comptime; |
| 480 | bool is_export; | ||
| 484 | bool is_extern; | 481 | bool is_extern; |
| 485 | // one or both of type and expr will be non null | 482 | // one or both of type and expr will be non null |
| 486 | AstNode *type; | 483 | AstNode *type; |
| 487 | AstNode *expr; | 484 | AstNode *expr; |
| 488 | // populated if this is an extern declaration | 485 | // populated if this is an extern declaration |
| 489 | Buf *lib_name; | 486 | Buf *lib_name; |
| 490 | // populated if the "align A" is present | 487 | // populated if the "align(A)" is present |
| 491 | AstNode *align_expr; | 488 | AstNode *align_expr; |
| 489 | // populated if the "section(S)" is present | ||
| 490 | AstNode *section_expr; | ||
| 492 | }; | 491 | }; |
| 493 | 492 | ||
| 494 | struct AstNodeErrorValueDecl { | 493 | struct AstNodeErrorValueDecl { |
| ... | @@ -659,6 +658,7 @@ struct AstNodeTestExpr { | ... | @@ -659,6 +658,7 @@ struct AstNodeTestExpr { |
| 659 | }; | 658 | }; |
| 660 | 659 | ||
| 661 | struct AstNodeWhileExpr { | 660 | struct AstNodeWhileExpr { |
| 661 | Buf *name; | ||
| 662 | AstNode *condition; | 662 | AstNode *condition; |
| 663 | Buf *var_symbol; | 663 | Buf *var_symbol; |
| 664 | bool var_is_ptr; | 664 | bool var_is_ptr; |
| ... | @@ -670,6 +670,7 @@ struct AstNodeWhileExpr { | ... | @@ -670,6 +670,7 @@ struct AstNodeWhileExpr { |
| 670 | }; | 670 | }; |
| 671 | 671 | ||
| 672 | struct AstNodeForExpr { | 672 | struct AstNodeForExpr { |
| 673 | Buf *name; | ||
| 673 | AstNode *array_expr; | 674 | AstNode *array_expr; |
| 674 | AstNode *elem_node; // always a symbol | 675 | AstNode *elem_node; // always a symbol |
| 675 | AstNode *index_node; // always a symbol, might be null | 676 | AstNode *index_node; // always a symbol, might be null |
| ... | @@ -701,11 +702,6 @@ struct AstNodeLabel { | ... | @@ -701,11 +702,6 @@ struct AstNodeLabel { |
| 701 | Buf *name; | 702 | Buf *name; |
| 702 | }; | 703 | }; |
| 703 | 704 | ||
| 704 | struct AstNodeGoto { | ||
| 705 | Buf *name; | ||
| 706 | bool is_inline; | ||
| 707 | }; | ||
| 708 | |||
| 709 | struct AstNodeCompTime { | 705 | struct AstNodeCompTime { |
| 710 | AstNode *expr; | 706 | AstNode *expr; |
| 711 | }; | 707 | }; |
| ... | @@ -833,11 +829,14 @@ struct AstNodeBoolLiteral { | ... | @@ -833,11 +829,14 @@ struct AstNodeBoolLiteral { |
| 833 | }; | 829 | }; |
| 834 | 830 | ||
| 835 | struct AstNodeBreakExpr { | 831 | struct AstNodeBreakExpr { |
| 832 | Buf *name; | ||
| 836 | AstNode *expr; // may be null | 833 | AstNode *expr; // may be null |
| 837 | }; | 834 | }; |
| 838 | 835 | ||
| 839 | struct AstNodeContinueExpr { | 836 | struct AstNodeContinueExpr { |
| 837 | Buf *name; | ||
| 840 | }; | 838 | }; |
| 839 | |||
| 841 | struct AstNodeUnreachableExpr { | 840 | struct AstNodeUnreachableExpr { |
| 842 | }; | 841 | }; |
| 843 | 842 | ||
| ... | @@ -883,7 +882,6 @@ struct AstNode { | ... | @@ -883,7 +882,6 @@ struct AstNode { |
| 883 | AstNodeSwitchProng switch_prong; | 882 | AstNodeSwitchProng switch_prong; |
| 884 | AstNodeSwitchRange switch_range; | 883 | AstNodeSwitchRange switch_range; |
| 885 | AstNodeLabel label; | 884 | AstNodeLabel label; |
| 886 | AstNodeGoto goto_expr; | ||
| 887 | AstNodeCompTime comptime_expr; | 885 | AstNodeCompTime comptime_expr; |
| 888 | AstNodeAsmExpr asm_expr; | 886 | AstNodeAsmExpr asm_expr; |
| 889 | AstNodeFieldAccessExpr field_access_expr; | 887 | AstNodeFieldAccessExpr field_access_expr; |
| ... | @@ -1177,6 +1175,11 @@ enum FnInline { | ... | @@ -1177,6 +1175,11 @@ enum FnInline { |
| 1177 | FnInlineNever, | 1175 | FnInlineNever, |
| 1178 | }; | 1176 | }; |
| 1179 | 1177 | ||
| 1178 | struct FnExport { | ||
| 1179 | Buf name; | ||
| 1180 | GlobalLinkageId linkage; | ||
| 1181 | }; | ||
| 1182 | |||
| 1180 | struct FnTableEntry { | 1183 | struct FnTableEntry { |
| 1181 | LLVMValueRef llvm_value; | 1184 | LLVMValueRef llvm_value; |
| 1182 | const char *llvm_name; | 1185 | const char *llvm_name; |
| ... | @@ -1204,12 +1207,11 @@ struct FnTableEntry { | ... | @@ -1204,12 +1207,11 @@ struct FnTableEntry { |
| 1204 | ZigList<IrInstruction *> alloca_list; | 1207 | ZigList<IrInstruction *> alloca_list; |
| 1205 | ZigList<VariableTableEntry *> variable_list; | 1208 | ZigList<VariableTableEntry *> variable_list; |
| 1206 | 1209 | ||
| 1207 | AstNode *set_global_section_node; | ||
| 1208 | Buf *section_name; | 1210 | Buf *section_name; |
| 1209 | AstNode *set_global_linkage_node; | ||
| 1210 | GlobalLinkageId linkage; | ||
| 1211 | AstNode *set_alignstack_node; | 1211 | AstNode *set_alignstack_node; |
| 1212 | uint32_t alignstack_value; | 1212 | uint32_t alignstack_value; |
| 1213 | |||
| 1214 | ZigList<FnExport> export_list; | ||
| 1213 | }; | 1215 | }; |
| 1214 | 1216 | ||
| 1215 | uint32_t fn_table_entry_hash(FnTableEntry*); | 1217 | uint32_t fn_table_entry_hash(FnTableEntry*); |
| ... | @@ -1258,8 +1260,6 @@ enum BuiltinFnId { | ... | @@ -1258,8 +1260,6 @@ enum BuiltinFnId { |
| 1258 | BuiltinFnIdSetFloatMode, | 1260 | BuiltinFnIdSetFloatMode, |
| 1259 | BuiltinFnIdTypeName, | 1261 | BuiltinFnIdTypeName, |
| 1260 | BuiltinFnIdCanImplicitCast, | 1262 | BuiltinFnIdCanImplicitCast, |
| 1261 | BuiltinFnIdSetGlobalSection, | ||
| 1262 | BuiltinFnIdSetGlobalLinkage, | ||
| 1263 | BuiltinFnIdPanic, | 1263 | BuiltinFnIdPanic, |
| 1264 | BuiltinFnIdPtrCast, | 1264 | BuiltinFnIdPtrCast, |
| 1265 | BuiltinFnIdBitCast, | 1265 | BuiltinFnIdBitCast, |
| ... | @@ -1270,6 +1270,7 @@ enum BuiltinFnId { | ... | @@ -1270,6 +1270,7 @@ enum BuiltinFnId { |
| 1270 | BuiltinFnIdFieldParentPtr, | 1270 | BuiltinFnIdFieldParentPtr, |
| 1271 | BuiltinFnIdOffsetOf, | 1271 | BuiltinFnIdOffsetOf, |
| 1272 | BuiltinFnIdInlineCall, | 1272 | BuiltinFnIdInlineCall, |
| 1273 | BuiltinFnIdNoInlineCall, | ||
| 1273 | BuiltinFnIdTypeId, | 1274 | BuiltinFnIdTypeId, |
| 1274 | BuiltinFnIdShlExact, | 1275 | BuiltinFnIdShlExact, |
| 1275 | BuiltinFnIdShrExact, | 1276 | BuiltinFnIdShrExact, |
| ... | @@ -1278,6 +1279,7 @@ enum BuiltinFnId { | ... | @@ -1278,6 +1279,7 @@ enum BuiltinFnId { |
| 1278 | BuiltinFnIdOpaqueType, | 1279 | BuiltinFnIdOpaqueType, |
| 1279 | BuiltinFnIdSetAlignStack, | 1280 | BuiltinFnIdSetAlignStack, |
| 1280 | BuiltinFnIdArgType, | 1281 | BuiltinFnIdArgType, |
| 1282 | BuiltinFnIdExport, | ||
| 1281 | }; | 1283 | }; |
| 1282 | 1284 | ||
| 1283 | struct BuiltinFnEntry { | 1285 | struct BuiltinFnEntry { |
| ... | @@ -1424,7 +1426,7 @@ struct CodeGen { | ... | @@ -1424,7 +1426,7 @@ struct CodeGen { |
| 1424 | HashMap<GenericFnTypeId *, FnTableEntry *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table; | 1426 | HashMap<GenericFnTypeId *, FnTableEntry *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table; |
| 1425 | HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table; | 1427 | HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table; |
| 1426 | HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table; | 1428 | HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table; |
| 1427 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names; | 1429 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; |
| 1428 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; | 1430 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; |
| 1429 | 1431 | ||
| 1430 | 1432 | ||
| ... | @@ -1439,7 +1441,7 @@ struct CodeGen { | ... | @@ -1439,7 +1441,7 @@ struct CodeGen { |
| 1439 | 1441 | ||
| 1440 | struct { | 1442 | struct { |
| 1441 | TypeTableEntry *entry_bool; | 1443 | TypeTableEntry *entry_bool; |
| 1442 | TypeTableEntry *entry_int[2][11]; // [signed,unsigned][2,3,4,5,6,7,8,16,32,64,128] | 1444 | TypeTableEntry *entry_int[2][12]; // [signed,unsigned][2,3,4,5,6,7,8,16,29,32,64,128] |
| 1443 | TypeTableEntry *entry_c_int[CIntTypeCount]; | 1445 | TypeTableEntry *entry_c_int[CIntTypeCount]; |
| 1444 | TypeTableEntry *entry_c_longdouble; | 1446 | TypeTableEntry *entry_c_longdouble; |
| 1445 | TypeTableEntry *entry_c_void; | 1447 | TypeTableEntry *entry_c_void; |
| ... | @@ -1639,12 +1641,6 @@ struct ErrorTableEntry { | ... | @@ -1639,12 +1641,6 @@ struct ErrorTableEntry { |
| 1639 | ConstExprValue *cached_error_name_val; | 1641 | ConstExprValue *cached_error_name_val; |
| 1640 | }; | 1642 | }; |
| 1641 | 1643 | ||
| 1642 | struct LabelTableEntry { | ||
| 1643 | AstNode *decl_node; | ||
| 1644 | IrBasicBlock *bb; | ||
| 1645 | bool used; | ||
| 1646 | }; | ||
| 1647 | |||
| 1648 | enum ScopeId { | 1644 | enum ScopeId { |
| 1649 | ScopeIdDecls, | 1645 | ScopeIdDecls, |
| 1650 | ScopeIdBlock, | 1646 | ScopeIdBlock, |
| ... | @@ -1688,7 +1684,12 @@ struct ScopeDecls { | ... | @@ -1688,7 +1684,12 @@ struct ScopeDecls { |
| 1688 | struct ScopeBlock { | 1684 | struct ScopeBlock { |
| 1689 | Scope base; | 1685 | Scope base; |
| 1690 | 1686 | ||
| 1691 | HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; | 1687 | Buf *name; |
| 1688 | IrBasicBlock *end_block; | ||
| 1689 | IrInstruction *is_comptime; | ||
| 1690 | ZigList<IrInstruction *> *incoming_values; | ||
| 1691 | ZigList<IrBasicBlock *> *incoming_blocks; | ||
| 1692 | |||
| 1692 | bool safety_off; | 1693 | bool safety_off; |
| 1693 | AstNode *safety_set_node; | 1694 | AstNode *safety_set_node; |
| 1694 | bool fast_math_off; | 1695 | bool fast_math_off; |
| ... | @@ -1734,6 +1735,7 @@ struct ScopeCImport { | ... | @@ -1734,6 +1735,7 @@ struct ScopeCImport { |
| 1734 | struct ScopeLoop { | 1735 | struct ScopeLoop { |
| 1735 | Scope base; | 1736 | Scope base; |
| 1736 | 1737 | ||
| 1738 | Buf *name; | ||
| 1737 | IrBasicBlock *break_block; | 1739 | IrBasicBlock *break_block; |
| 1738 | IrBasicBlock *continue_block; | 1740 | IrBasicBlock *continue_block; |
| 1739 | IrInstruction *is_comptime; | 1741 | IrInstruction *is_comptime; |
| ... | @@ -1885,8 +1887,6 @@ enum IrInstructionId { | ... | @@ -1885,8 +1887,6 @@ enum IrInstructionId { |
| 1885 | IrInstructionIdCheckStatementIsVoid, | 1887 | IrInstructionIdCheckStatementIsVoid, |
| 1886 | IrInstructionIdTypeName, | 1888 | IrInstructionIdTypeName, |
| 1887 | IrInstructionIdCanImplicitCast, | 1889 | IrInstructionIdCanImplicitCast, |
| 1888 | IrInstructionIdSetGlobalSection, | ||
| 1889 | IrInstructionIdSetGlobalLinkage, | ||
| 1890 | IrInstructionIdDeclRef, | 1890 | IrInstructionIdDeclRef, |
| 1891 | IrInstructionIdPanic, | 1891 | IrInstructionIdPanic, |
| 1892 | IrInstructionIdTagName, | 1892 | IrInstructionIdTagName, |
| ... | @@ -1900,6 +1900,7 @@ enum IrInstructionId { | ... | @@ -1900,6 +1900,7 @@ enum IrInstructionId { |
| 1900 | IrInstructionIdOpaqueType, | 1900 | IrInstructionIdOpaqueType, |
| 1901 | IrInstructionIdSetAlignStack, | 1901 | IrInstructionIdSetAlignStack, |
| 1902 | IrInstructionIdArgType, | 1902 | IrInstructionIdArgType, |
| 1903 | IrInstructionIdExport, | ||
| 1903 | }; | 1904 | }; |
| 1904 | 1905 | ||
| 1905 | struct IrInstruction { | 1906 | struct IrInstruction { |
| ... | @@ -2102,7 +2103,7 @@ struct IrInstructionCall { | ... | @@ -2102,7 +2103,7 @@ struct IrInstructionCall { |
| 2102 | IrInstruction **args; | 2103 | IrInstruction **args; |
| 2103 | bool is_comptime; | 2104 | bool is_comptime; |
| 2104 | LLVMValueRef tmp_ptr; | 2105 | LLVMValueRef tmp_ptr; |
| 2105 | bool is_inline; | 2106 | FnInline fn_inline; |
| 2106 | }; | 2107 | }; |
| 2107 | 2108 | ||
| 2108 | struct IrInstructionConst { | 2109 | struct IrInstructionConst { |
| ... | @@ -2625,20 +2626,6 @@ struct IrInstructionCanImplicitCast { | ... | @@ -2625,20 +2626,6 @@ struct IrInstructionCanImplicitCast { |
| 2625 | IrInstruction *target_value; | 2626 | IrInstruction *target_value; |
| 2626 | }; | 2627 | }; |
| 2627 | 2628 | ||
| 2628 | struct IrInstructionSetGlobalSection { | ||
| 2629 | IrInstruction base; | ||
| 2630 | |||
| 2631 | Tld *tld; | ||
| 2632 | IrInstruction *value; | ||
| 2633 | }; | ||
| 2634 | |||
| 2635 | struct IrInstructionSetGlobalLinkage { | ||
| 2636 | IrInstruction base; | ||
| 2637 | |||
| 2638 | Tld *tld; | ||
| 2639 | IrInstruction *value; | ||
| 2640 | }; | ||
| 2641 | |||
| 2642 | struct IrInstructionDeclRef { | 2629 | struct IrInstructionDeclRef { |
| 2643 | IrInstruction base; | 2630 | IrInstruction base; |
| 2644 | 2631 | ||
| ... | @@ -2727,6 +2714,14 @@ struct IrInstructionArgType { | ... | @@ -2727,6 +2714,14 @@ struct IrInstructionArgType { |
| 2727 | IrInstruction *arg_index; | 2714 | IrInstruction *arg_index; |
| 2728 | }; | 2715 | }; |
| 2729 | 2716 | ||
| 2717 | struct IrInstructionExport { | ||
| 2718 | IrInstruction base; | ||
| 2719 | |||
| 2720 | IrInstruction *name; | ||
| 2721 | IrInstruction *linkage; | ||
| 2722 | IrInstruction *target; | ||
| 2723 | }; | ||
| 2724 | |||
| 2730 | static const size_t slice_ptr_index = 0; | 2725 | static const size_t slice_ptr_index = 0; |
| 2731 | static const size_t slice_len_index = 1; | 2726 | static const size_t slice_len_index = 1; |
| 2732 | 2727 |
src/analyze.cpp+146-65| ... | @@ -110,7 +110,7 @@ ScopeBlock *create_block_scope(AstNode *node, Scope *parent) { | ... | @@ -110,7 +110,7 @@ ScopeBlock *create_block_scope(AstNode *node, Scope *parent) { |
| 110 | assert(node->type == NodeTypeBlock); | 110 | assert(node->type == NodeTypeBlock); |
| 111 | ScopeBlock *scope = allocate<ScopeBlock>(1); | 111 | ScopeBlock *scope = allocate<ScopeBlock>(1); |
| 112 | init_scope(&scope->base, ScopeIdBlock, node, parent); | 112 | init_scope(&scope->base, ScopeIdBlock, node, parent); |
| 113 | scope->label_table.init(1); | 113 | scope->name = node->data.block.name; |
| 114 | return scope; | 114 | return scope; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| ... | @@ -144,9 +144,15 @@ ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent) { | ... | @@ -144,9 +144,15 @@ ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent) { |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | ScopeLoop *create_loop_scope(AstNode *node, Scope *parent) { | 146 | ScopeLoop *create_loop_scope(AstNode *node, Scope *parent) { |
| 147 | assert(node->type == NodeTypeWhileExpr || node->type == NodeTypeForExpr); | ||
| 148 | ScopeLoop *scope = allocate<ScopeLoop>(1); | 147 | ScopeLoop *scope = allocate<ScopeLoop>(1); |
| 149 | init_scope(&scope->base, ScopeIdLoop, node, parent); | 148 | init_scope(&scope->base, ScopeIdLoop, node, parent); |
| 149 | if (node->type == NodeTypeWhileExpr) { | ||
| 150 | scope->name = node->data.while_expr.name; | ||
| 151 | } else if (node->type == NodeTypeForExpr) { | ||
| 152 | scope->name = node->data.for_expr.name; | ||
| 153 | } else { | ||
| 154 | zig_unreachable(); | ||
| 155 | } | ||
| 150 | return scope; | 156 | return scope; |
| 151 | } | 157 | } |
| 152 | 158 | ||
| ... | @@ -429,7 +435,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { | ... | @@ -429,7 +435,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { |
| 429 | ensure_complete_type(g, child_type); | 435 | ensure_complete_type(g, child_type); |
| 430 | 436 | ||
| 431 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe); | 437 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe); |
| 432 | assert(child_type->type_ref); | 438 | assert(child_type->type_ref || child_type->zero_bits); |
| 433 | assert(child_type->di_type); | 439 | assert(child_type->di_type); |
| 434 | entry->is_copyable = type_is_copyable(g, child_type); | 440 | entry->is_copyable = type_is_copyable(g, child_type); |
| 435 | 441 | ||
| ... | @@ -1062,7 +1068,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou | ... | @@ -1062,7 +1068,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou |
| 1062 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | 1068 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 1063 | 1069 | ||
| 1064 | if (fn_proto->cc == CallingConventionUnspecified) { | 1070 | if (fn_proto->cc == CallingConventionUnspecified) { |
| 1065 | bool extern_abi = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport); | 1071 | bool extern_abi = fn_proto->is_extern || fn_proto->is_export; |
| 1066 | fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified; | 1072 | fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified; |
| 1067 | } else { | 1073 | } else { |
| 1068 | fn_type_id->cc = fn_proto->cc; | 1074 | fn_type_id->cc = fn_proto->cc; |
| ... | @@ -1093,6 +1099,38 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_ | ... | @@ -1093,6 +1099,38 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_ |
| 1093 | return true; | 1099 | return true; |
| 1094 | } | 1100 | } |
| 1095 | 1101 | ||
| 1102 | static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) { | ||
| 1103 | TypeTableEntry *ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | ||
| 1104 | TypeTableEntry *str_type = get_slice_type(g, ptr_type); | ||
| 1105 | IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr); | ||
| 1106 | if (type_is_invalid(instr->value.type)) | ||
| 1107 | return false; | ||
| 1108 | |||
| 1109 | ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index]; | ||
| 1110 | ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index]; | ||
| 1111 | |||
| 1112 | assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); | ||
| 1113 | ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; | ||
| 1114 | expand_undef_array(g, array_val); | ||
| 1115 | size_t len = bigint_as_unsigned(&len_field->data.x_bigint); | ||
| 1116 | Buf *result = buf_alloc(); | ||
| 1117 | buf_resize(result, len); | ||
| 1118 | for (size_t i = 0; i < len; i += 1) { | ||
| 1119 | size_t new_index = ptr_field->data.x_ptr.data.base_array.elem_index + i; | ||
| 1120 | ConstExprValue *char_val = &array_val->data.x_array.s_none.elements[new_index]; | ||
| 1121 | if (char_val->special == ConstValSpecialUndef) { | ||
| 1122 | add_node_error(g, node, buf_sprintf("use of undefined value")); | ||
| 1123 | return false; | ||
| 1124 | } | ||
| 1125 | uint64_t big_c = bigint_as_unsigned(&char_val->data.x_bigint); | ||
| 1126 | assert(big_c <= UINT8_MAX); | ||
| 1127 | uint8_t c = (uint8_t)big_c; | ||
| 1128 | buf_ptr(result)[i] = c; | ||
| 1129 | } | ||
| 1130 | *out_buffer = result; | ||
| 1131 | return true; | ||
| 1132 | } | ||
| 1133 | |||
| 1096 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) { | 1134 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) { |
| 1097 | assert(proto_node->type == NodeTypeFnProto); | 1135 | assert(proto_node->type == NodeTypeFnProto); |
| 1098 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | 1136 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| ... | @@ -1130,6 +1168,15 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -1130,6 +1168,15 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1130 | } | 1168 | } |
| 1131 | 1169 | ||
| 1132 | TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); | 1170 | TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); |
| 1171 | if (fn_type_id.cc != CallingConventionUnspecified) { | ||
| 1172 | type_ensure_zero_bits_known(g, type_entry); | ||
| 1173 | if (!type_has_bits(type_entry)) { | ||
| 1174 | add_node_error(g, param_node->data.param_decl.type, | ||
| 1175 | buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", | ||
| 1176 | buf_ptr(&type_entry->name), calling_convention_name(fn_type_id.cc))); | ||
| 1177 | return g->builtin_types.entry_invalid; | ||
| 1178 | } | ||
| 1179 | } | ||
| 1133 | 1180 | ||
| 1134 | switch (type_entry->id) { | 1181 | switch (type_entry->id) { |
| 1135 | case TypeTableEntryIdInvalid: | 1182 | case TypeTableEntryIdInvalid: |
| ... | @@ -2227,7 +2274,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2227,7 +2274,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2227 | 2274 | ||
| 2228 | tag_type = new_type_table_entry(TypeTableEntryIdEnum); | 2275 | tag_type = new_type_table_entry(TypeTableEntryIdEnum); |
| 2229 | buf_resize(&tag_type->name, 0); | 2276 | buf_resize(&tag_type->name, 0); |
| 2230 | buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name)); | 2277 | buf_appendf(&tag_type->name, "@TagType(%s)", buf_ptr(&union_type->name)); |
| 2231 | tag_type->is_copyable = true; | 2278 | tag_type->is_copyable = true; |
| 2232 | tag_type->type_ref = tag_int_type->type_ref; | 2279 | tag_type->type_ref = tag_int_type->type_ref; |
| 2233 | tag_type->zero_bits = tag_int_type->zero_bits; | 2280 | tag_type->zero_bits = tag_int_type->zero_bits; |
| ... | @@ -2244,12 +2291,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2244,12 +2291,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2244 | TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node); | 2291 | TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node); |
| 2245 | if (type_is_invalid(enum_type)) { | 2292 | if (type_is_invalid(enum_type)) { |
| 2246 | union_type->data.unionation.is_invalid = true; | 2293 | union_type->data.unionation.is_invalid = true; |
| 2247 | union_type->data.unionation.embedded_in_current = false; | ||
| 2248 | return; | 2294 | return; |
| 2249 | } | 2295 | } |
| 2250 | if (enum_type->id != TypeTableEntryIdEnum) { | 2296 | if (enum_type->id != TypeTableEntryIdEnum) { |
| 2251 | union_type->data.unionation.is_invalid = true; | 2297 | union_type->data.unionation.is_invalid = true; |
| 2252 | union_type->data.unionation.embedded_in_current = false; | ||
| 2253 | add_node_error(g, enum_type_node, | 2298 | add_node_error(g, enum_type_node, |
| 2254 | buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name))); | 2299 | buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name))); |
| 2255 | return; | 2300 | return; |
| ... | @@ -2474,7 +2519,7 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { | ... | @@ -2474,7 +2519,7 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { |
| 2474 | buf_append_buf(buf, tld->name); | 2519 | buf_append_buf(buf, tld->name); |
| 2475 | } | 2520 | } |
| 2476 | 2521 | ||
| 2477 | FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) { | 2522 | FnTableEntry *create_fn_raw(FnInline inline_value) { |
| 2478 | FnTableEntry *fn_entry = allocate<FnTableEntry>(1); | 2523 | FnTableEntry *fn_entry = allocate<FnTableEntry>(1); |
| 2479 | 2524 | ||
| 2480 | fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; | 2525 | fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; |
| ... | @@ -2482,7 +2527,6 @@ FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) { | ... | @@ -2482,7 +2527,6 @@ FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) { |
| 2482 | fn_entry->analyzed_executable.fn_entry = fn_entry; | 2527 | fn_entry->analyzed_executable.fn_entry = fn_entry; |
| 2483 | fn_entry->ir_executable.fn_entry = fn_entry; | 2528 | fn_entry->ir_executable.fn_entry = fn_entry; |
| 2484 | fn_entry->fn_inline = inline_value; | 2529 | fn_entry->fn_inline = inline_value; |
| 2485 | fn_entry->linkage = linkage; | ||
| 2486 | 2530 | ||
| 2487 | return fn_entry; | 2531 | return fn_entry; |
| 2488 | } | 2532 | } |
| ... | @@ -2492,9 +2536,7 @@ FnTableEntry *create_fn(AstNode *proto_node) { | ... | @@ -2492,9 +2536,7 @@ FnTableEntry *create_fn(AstNode *proto_node) { |
| 2492 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | 2536 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 2493 | 2537 | ||
| 2494 | FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; | 2538 | FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; |
| 2495 | GlobalLinkageId linkage = (fn_proto->visib_mod == VisibModExport || proto_node->data.fn_proto.is_extern) ? | 2539 | FnTableEntry *fn_entry = create_fn_raw(inline_value); |
| 2496 | GlobalLinkageIdStrong : GlobalLinkageIdInternal; | ||
| 2497 | FnTableEntry *fn_entry = create_fn_raw(inline_value, linkage); | ||
| 2498 | 2540 | ||
| 2499 | fn_entry->proto_node = proto_node; | 2541 | fn_entry->proto_node = proto_node; |
| 2500 | fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : | 2542 | fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : |
| ... | @@ -2550,6 +2592,34 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) { | ... | @@ -2550,6 +2592,34 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) { |
| 2550 | return g->test_fn_type; | 2592 | return g->test_fn_type; |
| 2551 | } | 2593 | } |
| 2552 | 2594 | ||
| 2595 | void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc) { | ||
| 2596 | if (ccc) { | ||
| 2597 | if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) { | ||
| 2598 | g->have_c_main = true; | ||
| 2599 | g->windows_subsystem_windows = false; | ||
| 2600 | g->windows_subsystem_console = true; | ||
| 2601 | } else if (buf_eql_str(symbol_name, "WinMain") && | ||
| 2602 | g->zig_target.os == ZigLLVM_Win32) | ||
| 2603 | { | ||
| 2604 | g->have_winmain = true; | ||
| 2605 | g->windows_subsystem_windows = true; | ||
| 2606 | g->windows_subsystem_console = false; | ||
| 2607 | } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && | ||
| 2608 | g->zig_target.os == ZigLLVM_Win32) | ||
| 2609 | { | ||
| 2610 | g->have_winmain_crt_startup = true; | ||
| 2611 | } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && | ||
| 2612 | g->zig_target.os == ZigLLVM_Win32) | ||
| 2613 | { | ||
| 2614 | g->have_dllmain_crt_startup = true; | ||
| 2615 | } | ||
| 2616 | } | ||
| 2617 | FnExport *fn_export = fn_table_entry->export_list.add_one(); | ||
| 2618 | memset(fn_export, 0, sizeof(FnExport)); | ||
| 2619 | buf_init_from_buf(&fn_export->name, symbol_name); | ||
| 2620 | fn_export->linkage = linkage; | ||
| 2621 | } | ||
| 2622 | |||
| 2553 | static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | 2623 | static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2554 | ImportTableEntry *import = tld_fn->base.import; | 2624 | ImportTableEntry *import = tld_fn->base.import; |
| 2555 | AstNode *source_node = tld_fn->base.source_node; | 2625 | AstNode *source_node = tld_fn->base.source_node; |
| ... | @@ -2561,6 +2631,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -2561,6 +2631,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2561 | FnTableEntry *fn_table_entry = create_fn(source_node); | 2631 | FnTableEntry *fn_table_entry = create_fn(source_node); |
| 2562 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); | 2632 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); |
| 2563 | 2633 | ||
| 2634 | if (fn_proto->is_export) { | ||
| 2635 | bool ccc = (fn_proto->cc == CallingConventionUnspecified || fn_proto->cc == CallingConventionC); | ||
| 2636 | add_fn_export(g, fn_table_entry, &fn_table_entry->symbol_name, GlobalLinkageIdStrong, ccc); | ||
| 2637 | } | ||
| 2638 | |||
| 2564 | tld_fn->fn_entry = fn_table_entry; | 2639 | tld_fn->fn_entry = fn_table_entry; |
| 2565 | 2640 | ||
| 2566 | if (fn_table_entry->body_node) { | 2641 | if (fn_table_entry->body_node) { |
| ... | @@ -2574,7 +2649,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -2574,7 +2649,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2574 | add_node_error(g, param_node, buf_sprintf("missing parameter name")); | 2649 | add_node_error(g, param_node, buf_sprintf("missing parameter name")); |
| 2575 | } | 2650 | } |
| 2576 | } | 2651 | } |
| 2577 | } else if (fn_table_entry->linkage != GlobalLinkageIdInternal) { | 2652 | } else { |
| 2578 | g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base); | 2653 | g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base); |
| 2579 | } | 2654 | } |
| 2580 | 2655 | ||
| ... | @@ -2582,6 +2657,15 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -2582,6 +2657,15 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2582 | 2657 | ||
| 2583 | fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope); | 2658 | fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope); |
| 2584 | 2659 | ||
| 2660 | if (fn_proto->section_expr != nullptr) { | ||
| 2661 | if (fn_table_entry->body_node == nullptr) { | ||
| 2662 | add_node_error(g, fn_proto->section_expr, | ||
| 2663 | buf_sprintf("cannot set section of external function '%s'", buf_ptr(&fn_table_entry->symbol_name))); | ||
| 2664 | } else { | ||
| 2665 | analyze_const_string(g, child_scope, fn_proto->section_expr, &fn_table_entry->section_name); | ||
| 2666 | } | ||
| 2667 | } | ||
| 2668 | |||
| 2585 | if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) { | 2669 | if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) { |
| 2586 | tld_fn->base.resolution = TldResolutionInvalid; | 2670 | tld_fn->base.resolution = TldResolutionInvalid; |
| 2587 | return; | 2671 | return; |
| ... | @@ -2596,15 +2680,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -2596,15 +2680,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2596 | { | 2680 | { |
| 2597 | if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { | 2681 | if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { |
| 2598 | g->main_fn = fn_table_entry; | 2682 | g->main_fn = fn_table_entry; |
| 2599 | 2683 | TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); | |
| 2600 | if (tld_fn->base.visib_mod != VisibModExport) { | 2684 | TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; |
| 2601 | TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); | 2685 | if (actual_return_type != err_void) { |
| 2602 | TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; | 2686 | add_node_error(g, fn_proto->return_type, |
| 2603 | if (actual_return_type != err_void) { | 2687 | buf_sprintf("expected return type of main to be '%%void', instead is '%s'", |
| 2604 | add_node_error(g, fn_proto->return_type, | 2688 | buf_ptr(&actual_return_type->name))); |
| 2605 | buf_sprintf("expected return type of main to be '%%void', instead is '%s'", | ||
| 2606 | buf_ptr(&actual_return_type->name))); | ||
| 2607 | } | ||
| 2608 | } | 2689 | } |
| 2609 | } else if ((import->package == g->panic_package || g->have_pub_panic) && | 2690 | } else if ((import->package == g->panic_package || g->have_pub_panic) && |
| 2610 | buf_eql_str(&fn_table_entry->symbol_name, "panic")) | 2691 | buf_eql_str(&fn_table_entry->symbol_name, "panic")) |
| ... | @@ -2615,7 +2696,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -2615,7 +2696,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2615 | } | 2696 | } |
| 2616 | } | 2697 | } |
| 2617 | } else if (source_node->type == NodeTypeTestDecl) { | 2698 | } else if (source_node->type == NodeTypeTestDecl) { |
| 2618 | FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong); | 2699 | FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto); |
| 2619 | 2700 | ||
| 2620 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); | 2701 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); |
| 2621 | 2702 | ||
| ... | @@ -2642,17 +2723,23 @@ static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { | ... | @@ -2642,17 +2723,23 @@ static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { |
| 2642 | } | 2723 | } |
| 2643 | 2724 | ||
| 2644 | static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { | 2725 | static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { |
| 2645 | if (tld->visib_mod == VisibModExport) { | 2726 | bool is_export = false; |
| 2646 | g->resolve_queue.append(tld); | 2727 | if (tld->id == TldIdVar) { |
| 2728 | assert(tld->source_node->type == NodeTypeVariableDeclaration); | ||
| 2729 | is_export = tld->source_node->data.variable_declaration.is_export; | ||
| 2730 | } else if (tld->id == TldIdFn) { | ||
| 2731 | assert(tld->source_node->type == NodeTypeFnProto); | ||
| 2732 | is_export = tld->source_node->data.fn_proto.is_export; | ||
| 2647 | } | 2733 | } |
| 2734 | if (is_export) { | ||
| 2735 | g->resolve_queue.append(tld); | ||
| 2648 | 2736 | ||
| 2649 | if (tld->visib_mod == VisibModExport) { | 2737 | auto entry = g->exported_symbol_names.put_unique(tld->name, tld->source_node); |
| 2650 | auto entry = g->exported_symbol_names.put_unique(tld->name, tld); | ||
| 2651 | if (entry) { | 2738 | if (entry) { |
| 2652 | Tld *other_tld = entry->value; | 2739 | AstNode *other_source_node = entry->value; |
| 2653 | ErrorMsg *msg = add_node_error(g, tld->source_node, | 2740 | ErrorMsg *msg = add_node_error(g, tld->source_node, |
| 2654 | buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name))); | 2741 | buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name))); |
| 2655 | add_error_note(g, msg, other_tld->source_node, buf_sprintf("other symbol is here")); | 2742 | add_error_note(g, msg, other_source_node, buf_sprintf("other symbol here")); |
| 2656 | } | 2743 | } |
| 2657 | } | 2744 | } |
| 2658 | 2745 | ||
| ... | @@ -2731,7 +2818,6 @@ static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_s | ... | @@ -2731,7 +2818,6 @@ static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_s |
| 2731 | g->resolve_queue.append(&tld_comptime->base); | 2818 | g->resolve_queue.append(&tld_comptime->base); |
| 2732 | } | 2819 | } |
| 2733 | 2820 | ||
| 2734 | |||
| 2735 | void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, | 2821 | void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, |
| 2736 | Scope *parent_scope) | 2822 | Scope *parent_scope) |
| 2737 | { | 2823 | { |
| ... | @@ -2836,8 +2922,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { | ... | @@ -2836,8 +2922,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 2836 | case NodeTypeSwitchExpr: | 2922 | case NodeTypeSwitchExpr: |
| 2837 | case NodeTypeSwitchProng: | 2923 | case NodeTypeSwitchProng: |
| 2838 | case NodeTypeSwitchRange: | 2924 | case NodeTypeSwitchRange: |
| 2839 | case NodeTypeLabel: | ||
| 2840 | case NodeTypeGoto: | ||
| 2841 | case NodeTypeBreak: | 2925 | case NodeTypeBreak: |
| 2842 | case NodeTypeContinue: | 2926 | case NodeTypeContinue: |
| 2843 | case NodeTypeUnreachable: | 2927 | case NodeTypeUnreachable: |
| ... | @@ -2987,8 +3071,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | ... | @@ -2987,8 +3071,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 2987 | AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; | 3071 | AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; |
| 2988 | 3072 | ||
| 2989 | bool is_const = var_decl->is_const; | 3073 | bool is_const = var_decl->is_const; |
| 2990 | bool is_export = (tld_var->base.visib_mod == VisibModExport); | ||
| 2991 | bool is_extern = var_decl->is_extern; | 3074 | bool is_extern = var_decl->is_extern; |
| 3075 | bool is_export = var_decl->is_export; | ||
| 2992 | 3076 | ||
| 2993 | TypeTableEntry *explicit_type = nullptr; | 3077 | TypeTableEntry *explicit_type = nullptr; |
| 2994 | if (var_decl->type) { | 3078 | if (var_decl->type) { |
| ... | @@ -2996,9 +3080,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | ... | @@ -2996,9 +3080,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 2996 | explicit_type = validate_var_type(g, var_decl->type, proposed_type); | 3080 | explicit_type = validate_var_type(g, var_decl->type, proposed_type); |
| 2997 | } | 3081 | } |
| 2998 | 3082 | ||
| 2999 | if (is_export && is_extern) { | 3083 | assert(!is_export || !is_extern); |
| 3000 | add_node_error(g, source_node, buf_sprintf("variable is both export and extern")); | ||
| 3001 | } | ||
| 3002 | 3084 | ||
| 3003 | VarLinkage linkage; | 3085 | VarLinkage linkage; |
| 3004 | if (is_export) { | 3086 | if (is_export) { |
| ... | @@ -3009,7 +3091,6 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | ... | @@ -3009,7 +3091,6 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3009 | linkage = VarLinkageInternal; | 3091 | linkage = VarLinkageInternal; |
| 3010 | } | 3092 | } |
| 3011 | 3093 | ||
| 3012 | |||
| 3013 | IrInstruction *init_value = nullptr; | 3094 | IrInstruction *init_value = nullptr; |
| 3014 | 3095 | ||
| 3015 | // TODO more validation for types that can't be used for export/extern variables | 3096 | // TODO more validation for types that can't be used for export/extern variables |
| ... | @@ -3058,6 +3139,15 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | ... | @@ -3058,6 +3139,15 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3058 | } | 3139 | } |
| 3059 | } | 3140 | } |
| 3060 | 3141 | ||
| 3142 | if (var_decl->section_expr != nullptr) { | ||
| 3143 | if (var_decl->is_extern) { | ||
| 3144 | add_node_error(g, var_decl->section_expr, | ||
| 3145 | buf_sprintf("cannot set section of external variable '%s'", buf_ptr(var_decl->symbol))); | ||
| 3146 | } else if (!analyze_const_string(g, tld_var->base.parent_scope, var_decl->section_expr, &tld_var->section_name)) { | ||
| 3147 | tld_var->section_name = nullptr; | ||
| 3148 | } | ||
| 3149 | } | ||
| 3150 | |||
| 3061 | g->global_vars.append(tld_var); | 3151 | g->global_vars.append(tld_var); |
| 3062 | } | 3152 | } |
| 3063 | 3153 | ||
| ... | @@ -3319,7 +3409,7 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { | ... | @@ -3319,7 +3409,7 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 3319 | 3409 | ||
| 3320 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { | 3410 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 3321 | assert(type_entry->id == TypeTableEntryIdUnion); | 3411 | assert(type_entry->id == TypeTableEntryIdUnion); |
| 3322 | assert(type_entry->data.unionation.complete); | 3412 | assert(type_entry->data.unionation.zero_bits_known); |
| 3323 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { | 3413 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { |
| 3324 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; | 3414 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; |
| 3325 | if (buf_eql_buf(field->enum_field->name, name)) { | 3415 | if (buf_eql_buf(field->enum_field->name, name)) { |
| ... | @@ -3331,7 +3421,7 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { | ... | @@ -3331,7 +3421,7 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 3331 | 3421 | ||
| 3332 | TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) { | 3422 | TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) { |
| 3333 | assert(type_entry->id == TypeTableEntryIdUnion); | 3423 | assert(type_entry->id == TypeTableEntryIdUnion); |
| 3334 | assert(type_entry->data.unionation.complete); | 3424 | assert(type_entry->data.unionation.zero_bits_known); |
| 3335 | assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX); | 3425 | assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX); |
| 3336 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { | 3426 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { |
| 3337 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; | 3427 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; |
| ... | @@ -3726,8 +3816,10 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a | ... | @@ -3726,8 +3816,10 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a |
| 3726 | Buf *proto_name = proto_node->data.fn_proto.name; | 3816 | Buf *proto_name = proto_node->data.fn_proto.name; |
| 3727 | 3817 | ||
| 3728 | bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub); | 3818 | bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub); |
| 3819 | bool ok_cc = (proto_node->data.fn_proto.cc == CallingConventionUnspecified || | ||
| 3820 | proto_node->data.fn_proto.cc == CallingConventionCold); | ||
| 3729 | 3821 | ||
| 3730 | if (is_pub) { | 3822 | if (is_pub && ok_cc) { |
| 3731 | if (buf_eql_str(proto_name, "main")) { | 3823 | if (buf_eql_str(proto_name, "main")) { |
| 3732 | g->have_pub_main = true; | 3824 | g->have_pub_main = true; |
| 3733 | g->windows_subsystem_windows = false; | 3825 | g->windows_subsystem_windows = false; |
| ... | @@ -3735,28 +3827,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a | ... | @@ -3735,28 +3827,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a |
| 3735 | } else if (buf_eql_str(proto_name, "panic")) { | 3827 | } else if (buf_eql_str(proto_name, "panic")) { |
| 3736 | g->have_pub_panic = true; | 3828 | g->have_pub_panic = true; |
| 3737 | } | 3829 | } |
| 3738 | } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "main") && | ||
| 3739 | g->libc_link_lib != nullptr) | ||
| 3740 | { | ||
| 3741 | g->have_c_main = true; | ||
| 3742 | g->windows_subsystem_windows = false; | ||
| 3743 | g->windows_subsystem_console = true; | ||
| 3744 | } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "WinMain") && | ||
| 3745 | g->zig_target.os == ZigLLVM_Win32) | ||
| 3746 | { | ||
| 3747 | g->have_winmain = true; | ||
| 3748 | g->windows_subsystem_windows = true; | ||
| 3749 | g->windows_subsystem_console = false; | ||
| 3750 | } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && | ||
| 3751 | buf_eql_str(proto_name, "WinMainCRTStartup") && g->zig_target.os == ZigLLVM_Win32) | ||
| 3752 | { | ||
| 3753 | g->have_winmain_crt_startup = true; | ||
| 3754 | } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && | ||
| 3755 | buf_eql_str(proto_name, "DllMainCRTStartup") && g->zig_target.os == ZigLLVM_Win32) | ||
| 3756 | { | ||
| 3757 | g->have_dllmain_crt_startup = true; | ||
| 3758 | } | 3830 | } |
| 3759 | |||
| 3760 | } | 3831 | } |
| 3761 | } | 3832 | } |
| 3762 | 3833 | ||
| ... | @@ -3820,12 +3891,14 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_b | ... | @@ -3820,12 +3891,14 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_b |
| 3820 | index = 6; | 3891 | index = 6; |
| 3821 | } else if (size_in_bits == 16) { | 3892 | } else if (size_in_bits == 16) { |
| 3822 | index = 7; | 3893 | index = 7; |
| 3823 | } else if (size_in_bits == 32) { | 3894 | } else if (size_in_bits == 29) { |
| 3824 | index = 8; | 3895 | index = 8; |
| 3825 | } else if (size_in_bits == 64) { | 3896 | } else if (size_in_bits == 32) { |
| 3826 | index = 9; | 3897 | index = 9; |
| 3827 | } else if (size_in_bits == 128) { | 3898 | } else if (size_in_bits == 64) { |
| 3828 | index = 10; | 3899 | index = 10; |
| 3900 | } else if (size_in_bits == 128) { | ||
| 3901 | index = 11; | ||
| 3829 | } else { | 3902 | } else { |
| 3830 | return nullptr; | 3903 | return nullptr; |
| 3831 | } | 3904 | } |
| ... | @@ -3888,7 +3961,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { | ... | @@ -3888,7 +3961,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 3888 | return false; | 3961 | return false; |
| 3889 | case TypeTableEntryIdArray: | 3962 | case TypeTableEntryIdArray: |
| 3890 | case TypeTableEntryIdStruct: | 3963 | case TypeTableEntryIdStruct: |
| 3891 | case TypeTableEntryIdUnion: | ||
| 3892 | return type_has_bits(type_entry); | 3964 | return type_has_bits(type_entry); |
| 3893 | case TypeTableEntryIdErrorUnion: | 3965 | case TypeTableEntryIdErrorUnion: |
| 3894 | return type_has_bits(type_entry->data.error.child_type); | 3966 | return type_has_bits(type_entry->data.error.child_type); |
| ... | @@ -3896,6 +3968,14 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { | ... | @@ -3896,6 +3968,14 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 3896 | return type_has_bits(type_entry->data.maybe.child_type) && | 3968 | return type_has_bits(type_entry->data.maybe.child_type) && |
| 3897 | type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && | 3969 | type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && |
| 3898 | type_entry->data.maybe.child_type->id != TypeTableEntryIdFn; | 3970 | type_entry->data.maybe.child_type->id != TypeTableEntryIdFn; |
| 3971 | case TypeTableEntryIdUnion: | ||
| 3972 | assert(type_entry->data.unionation.complete); | ||
| 3973 | if (type_entry->data.unionation.gen_field_count == 0) | ||
| 3974 | return false; | ||
| 3975 | if (!type_has_bits(type_entry)) | ||
| 3976 | return false; | ||
| 3977 | return true; | ||
| 3978 | |||
| 3899 | } | 3979 | } |
| 3900 | zig_unreachable(); | 3980 | zig_unreachable(); |
| 3901 | } | 3981 | } |
| ... | @@ -5438,3 +5518,4 @@ uint32_t type_ptr_hash(const TypeTableEntry *ptr) { | ... | @@ -5438,3 +5518,4 @@ uint32_t type_ptr_hash(const TypeTableEntry *ptr) { |
| 5438 | bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) { | 5518 | bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) { |
| 5439 | return a == b; | 5519 | return a == b; |
| 5440 | } | 5520 | } |
| 5521 |
src/analyze.hpp+4| ... | @@ -180,5 +180,9 @@ void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name); | ... | @@ -180,5 +180,9 @@ void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name); |
| 180 | 180 | ||
| 181 | uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry); | 181 | uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry); |
| 182 | TypeTableEntry *get_align_amt_type(CodeGen *g); | 182 | TypeTableEntry *get_align_amt_type(CodeGen *g); |
| 183 | PackageTableEntry *new_anonymous_package(void); | ||
| 184 | |||
| 185 | Buf *const_value_to_buffer(ConstExprValue *const_val); | ||
| 186 | void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc); | ||
| 183 | 187 | ||
| 184 | #endif | 188 | #endif |
src/ast_render.cpp+48-25| ... | @@ -78,7 +78,6 @@ static const char *visib_mod_string(VisibMod mod) { | ... | @@ -78,7 +78,6 @@ static const char *visib_mod_string(VisibMod mod) { |
| 78 | switch (mod) { | 78 | switch (mod) { |
| 79 | case VisibModPub: return "pub "; | 79 | case VisibModPub: return "pub "; |
| 80 | case VisibModPrivate: return ""; | 80 | case VisibModPrivate: return ""; |
| 81 | case VisibModExport: return "export "; | ||
| 82 | } | 81 | } |
| 83 | zig_unreachable(); | 82 | zig_unreachable(); |
| 84 | } | 83 | } |
| ... | @@ -112,6 +111,10 @@ static const char *extern_string(bool is_extern) { | ... | @@ -112,6 +111,10 @@ static const char *extern_string(bool is_extern) { |
| 112 | return is_extern ? "extern " : ""; | 111 | return is_extern ? "extern " : ""; |
| 113 | } | 112 | } |
| 114 | 113 | ||
| 114 | static const char *export_string(bool is_export) { | ||
| 115 | return is_export ? "export " : ""; | ||
| 116 | } | ||
| 117 | |||
| 115 | //static const char *calling_convention_string(CallingConvention cc) { | 118 | //static const char *calling_convention_string(CallingConvention cc) { |
| 116 | // switch (cc) { | 119 | // switch (cc) { |
| 117 | // case CallingConventionUnspecified: return ""; | 120 | // case CallingConventionUnspecified: return ""; |
| ... | @@ -212,10 +215,6 @@ static const char *node_type_str(NodeType node_type) { | ... | @@ -212,10 +215,6 @@ static const char *node_type_str(NodeType node_type) { |
| 212 | return "SwitchProng"; | 215 | return "SwitchProng"; |
| 213 | case NodeTypeSwitchRange: | 216 | case NodeTypeSwitchRange: |
| 214 | return "SwitchRange"; | 217 | return "SwitchRange"; |
| 215 | case NodeTypeLabel: | ||
| 216 | return "Label"; | ||
| 217 | case NodeTypeGoto: | ||
| 218 | return "Goto"; | ||
| 219 | case NodeTypeCompTime: | 218 | case NodeTypeCompTime: |
| 220 | return "CompTime"; | 219 | return "CompTime"; |
| 221 | case NodeTypeBreak: | 220 | case NodeTypeBreak: |
| ... | @@ -388,7 +387,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -388,7 +387,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 388 | switch (node->type) { | 387 | switch (node->type) { |
| 389 | case NodeTypeSwitchProng: | 388 | case NodeTypeSwitchProng: |
| 390 | case NodeTypeSwitchRange: | 389 | case NodeTypeSwitchRange: |
| 391 | case NodeTypeLabel: | ||
| 392 | case NodeTypeStructValueField: | 390 | case NodeTypeStructValueField: |
| 393 | zig_unreachable(); | 391 | zig_unreachable(); |
| 394 | case NodeTypeRoot: | 392 | case NodeTypeRoot: |
| ... | @@ -411,8 +409,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -411,8 +409,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 411 | { | 409 | { |
| 412 | const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); | 410 | const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); |
| 413 | const char *extern_str = extern_string(node->data.fn_proto.is_extern); | 411 | const char *extern_str = extern_string(node->data.fn_proto.is_extern); |
| 412 | const char *export_str = export_string(node->data.fn_proto.is_export); | ||
| 414 | const char *inline_str = inline_string(node->data.fn_proto.is_inline); | 413 | const char *inline_str = inline_string(node->data.fn_proto.is_inline); |
| 415 | fprintf(ar->f, "%s%s%sfn", pub_str, inline_str, extern_str); | 414 | fprintf(ar->f, "%s%s%s%sfn", pub_str, inline_str, export_str, extern_str); |
| 416 | if (node->data.fn_proto.name != nullptr) { | 415 | if (node->data.fn_proto.name != nullptr) { |
| 417 | fprintf(ar->f, " "); | 416 | fprintf(ar->f, " "); |
| 418 | print_symbol(ar, node->data.fn_proto.name); | 417 | print_symbol(ar, node->data.fn_proto.name); |
| ... | @@ -440,6 +439,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -440,6 +439,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 440 | } | 439 | } |
| 441 | } | 440 | } |
| 442 | fprintf(ar->f, ")"); | 441 | fprintf(ar->f, ")"); |
| 442 | if (node->data.fn_proto.align_expr) { | ||
| 443 | fprintf(ar->f, " align("); | ||
| 444 | render_node_grouped(ar, node->data.fn_proto.align_expr); | ||
| 445 | fprintf(ar->f, ")"); | ||
| 446 | } | ||
| 447 | if (node->data.fn_proto.section_expr) { | ||
| 448 | fprintf(ar->f, " section("); | ||
| 449 | render_node_grouped(ar, node->data.fn_proto.section_expr); | ||
| 450 | fprintf(ar->f, ")"); | ||
| 451 | } | ||
| 443 | 452 | ||
| 444 | AstNode *return_type_node = node->data.fn_proto.return_type; | 453 | AstNode *return_type_node = node->data.fn_proto.return_type; |
| 445 | if (return_type_node != nullptr) { | 454 | if (return_type_node != nullptr) { |
| ... | @@ -456,6 +465,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -456,6 +465,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 456 | break; | 465 | break; |
| 457 | } | 466 | } |
| 458 | case NodeTypeBlock: | 467 | case NodeTypeBlock: |
| 468 | if (node->data.block.name != nullptr) { | ||
| 469 | fprintf(ar->f, "%s: ", buf_ptr(node->data.block.name)); | ||
| 470 | } | ||
| 459 | if (node->data.block.statements.length == 0) { | 471 | if (node->data.block.statements.length == 0) { |
| 460 | fprintf(ar->f, "{}"); | 472 | fprintf(ar->f, "{}"); |
| 461 | break; | 473 | break; |
| ... | @@ -464,19 +476,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -464,19 +476,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 464 | ar->indent += ar->indent_size; | 476 | ar->indent += ar->indent_size; |
| 465 | for (size_t i = 0; i < node->data.block.statements.length; i += 1) { | 477 | for (size_t i = 0; i < node->data.block.statements.length; i += 1) { |
| 466 | AstNode *statement = node->data.block.statements.at(i); | 478 | AstNode *statement = node->data.block.statements.at(i); |
| 467 | if (statement->type == NodeTypeLabel) { | ||
| 468 | ar->indent -= ar->indent_size; | ||
| 469 | print_indent(ar); | ||
| 470 | fprintf(ar->f, "%s:\n", buf_ptr(statement->data.label.name)); | ||
| 471 | ar->indent += ar->indent_size; | ||
| 472 | continue; | ||
| 473 | } | ||
| 474 | print_indent(ar); | 479 | print_indent(ar); |
| 475 | render_node_grouped(ar, statement); | 480 | render_node_grouped(ar, statement); |
| 476 | if (!(i == node->data.block.statements.length - 1 && | 481 | fprintf(ar->f, ";"); |
| 477 | node->data.block.last_statement_is_result_expression)) { | ||
| 478 | fprintf(ar->f, ";"); | ||
| 479 | } | ||
| 480 | fprintf(ar->f, "\n"); | 482 | fprintf(ar->f, "\n"); |
| 481 | } | 483 | } |
| 482 | ar->indent -= ar->indent_size; | 484 | ar->indent -= ar->indent_size; |
| ... | @@ -501,6 +503,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -501,6 +503,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 501 | case NodeTypeBreak: | 503 | case NodeTypeBreak: |
| 502 | { | 504 | { |
| 503 | fprintf(ar->f, "break"); | 505 | fprintf(ar->f, "break"); |
| 506 | if (node->data.break_expr.name != nullptr) { | ||
| 507 | fprintf(ar->f, " :%s", buf_ptr(node->data.break_expr.name)); | ||
| 508 | } | ||
| 504 | if (node->data.break_expr.expr) { | 509 | if (node->data.break_expr.expr) { |
| 505 | fprintf(ar->f, " "); | 510 | fprintf(ar->f, " "); |
| 506 | render_node_grouped(ar, node->data.break_expr.expr); | 511 | render_node_grouped(ar, node->data.break_expr.expr); |
| ... | @@ -526,6 +531,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -526,6 +531,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 526 | fprintf(ar->f, ": "); | 531 | fprintf(ar->f, ": "); |
| 527 | render_node_grouped(ar, node->data.variable_declaration.type); | 532 | render_node_grouped(ar, node->data.variable_declaration.type); |
| 528 | } | 533 | } |
| 534 | if (node->data.variable_declaration.align_expr) { | ||
| 535 | fprintf(ar->f, "align("); | ||
| 536 | render_node_grouped(ar, node->data.variable_declaration.align_expr); | ||
| 537 | fprintf(ar->f, ") "); | ||
| 538 | } | ||
| 539 | if (node->data.variable_declaration.section_expr) { | ||
| 540 | fprintf(ar->f, "section("); | ||
| 541 | render_node_grouped(ar, node->data.variable_declaration.section_expr); | ||
| 542 | fprintf(ar->f, ") "); | ||
| 543 | } | ||
| 529 | if (node->data.variable_declaration.expr) { | 544 | if (node->data.variable_declaration.expr) { |
| 530 | fprintf(ar->f, " = "); | 545 | fprintf(ar->f, " = "); |
| 531 | render_node_grouped(ar, node->data.variable_declaration.expr); | 546 | render_node_grouped(ar, node->data.variable_declaration.expr); |
| ... | @@ -584,12 +599,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -584,12 +599,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 584 | PrefixOp op = node->data.prefix_op_expr.prefix_op; | 599 | PrefixOp op = node->data.prefix_op_expr.prefix_op; |
| 585 | fprintf(ar->f, "%s", prefix_op_str(op)); | 600 | fprintf(ar->f, "%s", prefix_op_str(op)); |
| 586 | 601 | ||
| 587 | render_node_ungrouped(ar, node->data.prefix_op_expr.primary_expr); | 602 | AstNode *child_node = node->data.prefix_op_expr.primary_expr; |
| 603 | bool new_grouped = child_node->type == NodeTypePrefixOpExpr || child_node->type == NodeTypeAddrOfExpr; | ||
| 604 | render_node_extra(ar, child_node, new_grouped); | ||
| 588 | if (!grouped) fprintf(ar->f, ")"); | 605 | if (!grouped) fprintf(ar->f, ")"); |
| 589 | break; | 606 | break; |
| 590 | } | 607 | } |
| 591 | case NodeTypeAddrOfExpr: | 608 | case NodeTypeAddrOfExpr: |
| 592 | { | 609 | { |
| 610 | if (!grouped) fprintf(ar->f, "("); | ||
| 593 | fprintf(ar->f, "&"); | 611 | fprintf(ar->f, "&"); |
| 594 | if (node->data.addr_of_expr.align_expr != nullptr) { | 612 | if (node->data.addr_of_expr.align_expr != nullptr) { |
| 595 | fprintf(ar->f, "align("); | 613 | fprintf(ar->f, "align("); |
| ... | @@ -617,6 +635,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -617,6 +635,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 617 | } | 635 | } |
| 618 | 636 | ||
| 619 | render_node_ungrouped(ar, node->data.addr_of_expr.op_expr); | 637 | render_node_ungrouped(ar, node->data.addr_of_expr.op_expr); |
| 638 | if (!grouped) fprintf(ar->f, ")"); | ||
| 620 | break; | 639 | break; |
| 621 | } | 640 | } |
| 622 | case NodeTypeFnCallExpr: | 641 | case NodeTypeFnCallExpr: |
| ... | @@ -625,7 +644,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -625,7 +644,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 625 | fprintf(ar->f, "@"); | 644 | fprintf(ar->f, "@"); |
| 626 | } | 645 | } |
| 627 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; | 646 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; |
| 628 | bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr); | 647 | bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr); |
| 629 | render_node_extra(ar, fn_ref_node, grouped); | 648 | render_node_extra(ar, fn_ref_node, grouped); |
| 630 | fprintf(ar->f, "("); | 649 | fprintf(ar->f, "("); |
| 631 | for (size_t i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | 650 | for (size_t i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| ... | @@ -800,6 +819,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -800,6 +819,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 800 | } | 819 | } |
| 801 | case NodeTypeWhileExpr: | 820 | case NodeTypeWhileExpr: |
| 802 | { | 821 | { |
| 822 | if (node->data.while_expr.name != nullptr) { | ||
| 823 | fprintf(ar->f, "%s: ", buf_ptr(node->data.while_expr.name)); | ||
| 824 | } | ||
| 803 | const char *inline_str = node->data.while_expr.is_inline ? "inline " : ""; | 825 | const char *inline_str = node->data.while_expr.is_inline ? "inline " : ""; |
| 804 | fprintf(ar->f, "%swhile (", inline_str); | 826 | fprintf(ar->f, "%swhile (", inline_str); |
| 805 | render_node_grouped(ar, node->data.while_expr.condition); | 827 | render_node_grouped(ar, node->data.while_expr.condition); |
| ... | @@ -929,11 +951,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -929,11 +951,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 929 | fprintf(ar->f, "}"); | 951 | fprintf(ar->f, "}"); |
| 930 | break; | 952 | break; |
| 931 | } | 953 | } |
| 932 | case NodeTypeGoto: | ||
| 933 | { | ||
| 934 | fprintf(ar->f, "goto %s", buf_ptr(node->data.goto_expr.name)); | ||
| 935 | break; | ||
| 936 | } | ||
| 937 | case NodeTypeCompTime: | 954 | case NodeTypeCompTime: |
| 938 | { | 955 | { |
| 939 | fprintf(ar->f, "comptime "); | 956 | fprintf(ar->f, "comptime "); |
| ... | @@ -942,6 +959,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -942,6 +959,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 942 | } | 959 | } |
| 943 | case NodeTypeForExpr: | 960 | case NodeTypeForExpr: |
| 944 | { | 961 | { |
| 962 | if (node->data.for_expr.name != nullptr) { | ||
| 963 | fprintf(ar->f, "%s: ", buf_ptr(node->data.for_expr.name)); | ||
| 964 | } | ||
| 945 | const char *inline_str = node->data.for_expr.is_inline ? "inline " : ""; | 965 | const char *inline_str = node->data.for_expr.is_inline ? "inline " : ""; |
| 946 | fprintf(ar->f, "%sfor (", inline_str); | 966 | fprintf(ar->f, "%sfor (", inline_str); |
| 947 | render_node_grouped(ar, node->data.for_expr.array_expr); | 967 | render_node_grouped(ar, node->data.for_expr.array_expr); |
| ... | @@ -967,6 +987,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -967,6 +987,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 967 | case NodeTypeContinue: | 987 | case NodeTypeContinue: |
| 968 | { | 988 | { |
| 969 | fprintf(ar->f, "continue"); | 989 | fprintf(ar->f, "continue"); |
| 990 | if (node->data.continue_expr.name != nullptr) { | ||
| 991 | fprintf(ar->f, " :%s", buf_ptr(node->data.continue_expr.name)); | ||
| 992 | } | ||
| 970 | break; | 993 | break; |
| 971 | } | 994 | } |
| 972 | case NodeTypeUnreachable: | 995 | case NodeTypeUnreachable: |
src/c_tokenizer.cpp+15| ... | @@ -121,6 +121,9 @@ static void begin_token(CTokenize *ctok, CTokId id) { | ... | @@ -121,6 +121,9 @@ static void begin_token(CTokenize *ctok, CTokId id) { |
| 121 | case CTokIdRParen: | 121 | case CTokIdRParen: |
| 122 | case CTokIdEOF: | 122 | case CTokIdEOF: |
| 123 | case CTokIdDot: | 123 | case CTokIdDot: |
| 124 | case CTokIdAsterisk: | ||
| 125 | case CTokIdBang: | ||
| 126 | case CTokIdTilde: | ||
| 124 | break; | 127 | break; |
| 125 | } | 128 | } |
| 126 | } | 129 | } |
| ... | @@ -228,10 +231,22 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { | ... | @@ -228,10 +231,22 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { |
| 228 | begin_token(ctok, CTokIdRParen); | 231 | begin_token(ctok, CTokIdRParen); |
| 229 | end_token(ctok); | 232 | end_token(ctok); |
| 230 | break; | 233 | break; |
| 234 | case '*': | ||
| 235 | begin_token(ctok, CTokIdAsterisk); | ||
| 236 | end_token(ctok); | ||
| 237 | break; | ||
| 231 | case '-': | 238 | case '-': |
| 232 | begin_token(ctok, CTokIdMinus); | 239 | begin_token(ctok, CTokIdMinus); |
| 233 | end_token(ctok); | 240 | end_token(ctok); |
| 234 | break; | 241 | break; |
| 242 | case '!': | ||
| 243 | begin_token(ctok, CTokIdBang); | ||
| 244 | end_token(ctok); | ||
| 245 | break; | ||
| 246 | case '~': | ||
| 247 | begin_token(ctok, CTokIdTilde); | ||
| 248 | end_token(ctok); | ||
| 249 | break; | ||
| 235 | default: | 250 | default: |
| 236 | return mark_error(ctok); | 251 | return mark_error(ctok); |
| 237 | } | 252 | } |
src/c_tokenizer.hpp+3| ... | @@ -22,6 +22,9 @@ enum CTokId { | ... | @@ -22,6 +22,9 @@ enum CTokId { |
| 22 | CTokIdRParen, | 22 | CTokIdRParen, |
| 23 | CTokIdEOF, | 23 | CTokIdEOF, |
| 24 | CTokIdDot, | 24 | CTokIdDot, |
| 25 | CTokIdAsterisk, | ||
| 26 | CTokIdBang, | ||
| 27 | CTokIdTilde, | ||
| 25 | }; | 28 | }; |
| 26 | 29 | ||
| 27 | enum CNumLitSuffix { | 30 | enum CNumLitSuffix { |
src/codegen.cpp+139-60| ... | @@ -55,6 +55,10 @@ static PackageTableEntry *new_package(const char *root_src_dir, const char *root | ... | @@ -55,6 +55,10 @@ static PackageTableEntry *new_package(const char *root_src_dir, const char *root |
| 55 | return entry; | 55 | return entry; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | PackageTableEntry *new_anonymous_package(void) { | ||
| 59 | return new_package("", ""); | ||
| 60 | } | ||
| 61 | |||
| 58 | CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, | 62 | CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, |
| 59 | Buf *zig_lib_dir) | 63 | Buf *zig_lib_dir) |
| 60 | { | 64 | { |
| ... | @@ -387,24 +391,51 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { | ... | @@ -387,24 +391,51 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { |
| 387 | } | 391 | } |
| 388 | } | 392 | } |
| 389 | 393 | ||
| 394 | static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { | ||
| 395 | switch (id) { | ||
| 396 | case GlobalLinkageIdInternal: | ||
| 397 | return LLVMInternalLinkage; | ||
| 398 | case GlobalLinkageIdStrong: | ||
| 399 | return LLVMExternalLinkage; | ||
| 400 | case GlobalLinkageIdWeak: | ||
| 401 | return LLVMWeakODRLinkage; | ||
| 402 | case GlobalLinkageIdLinkOnce: | ||
| 403 | return LLVMLinkOnceODRLinkage; | ||
| 404 | } | ||
| 405 | zig_unreachable(); | ||
| 406 | } | ||
| 407 | |||
| 390 | static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { | 408 | static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 391 | if (fn_table_entry->llvm_value) | 409 | if (fn_table_entry->llvm_value) |
| 392 | return fn_table_entry->llvm_value; | 410 | return fn_table_entry->llvm_value; |
| 393 | 411 | ||
| 394 | bool external_linkage = (fn_table_entry->linkage != GlobalLinkageIdInternal); | 412 | Buf *unmangled_name = &fn_table_entry->symbol_name; |
| 395 | Buf *symbol_name = get_mangled_name(g, &fn_table_entry->symbol_name, external_linkage); | 413 | Buf *symbol_name; |
| 414 | GlobalLinkageId linkage; | ||
| 415 | if (fn_table_entry->body_node == nullptr) { | ||
| 416 | symbol_name = unmangled_name; | ||
| 417 | linkage = GlobalLinkageIdStrong; | ||
| 418 | } else if (fn_table_entry->export_list.length == 0) { | ||
| 419 | symbol_name = get_mangled_name(g, unmangled_name, false); | ||
| 420 | linkage = GlobalLinkageIdInternal; | ||
| 421 | } else { | ||
| 422 | FnExport *fn_export = &fn_table_entry->export_list.items[0]; | ||
| 423 | symbol_name = &fn_export->name; | ||
| 424 | linkage = fn_export->linkage; | ||
| 425 | } | ||
| 396 | 426 | ||
| 427 | bool external_linkage = linkage != GlobalLinkageIdInternal; | ||
| 397 | if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall && external_linkage && | 428 | if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall && external_linkage && |
| 398 | g->zig_target.arch.arch == ZigLLVM_x86) | 429 | g->zig_target.arch.arch == ZigLLVM_x86) |
| 399 | { | 430 | { |
| 400 | // prevent name mangling | 431 | // prevent llvm name mangling |
| 401 | symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name)); | 432 | symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name)); |
| 402 | } | 433 | } |
| 403 | 434 | ||
| 404 | 435 | ||
| 405 | TypeTableEntry *fn_type = fn_table_entry->type_entry; | 436 | TypeTableEntry *fn_type = fn_table_entry->type_entry; |
| 406 | LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref; | 437 | LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref; |
| 407 | if (external_linkage && fn_table_entry->body_node == nullptr) { | 438 | if (fn_table_entry->body_node == nullptr) { |
| 408 | LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name)); | 439 | LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name)); |
| 409 | if (existing_llvm_fn) { | 440 | if (existing_llvm_fn) { |
| 410 | fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0)); | 441 | fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0)); |
| ... | @@ -414,6 +445,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { | ... | @@ -414,6 +445,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 414 | } | 445 | } |
| 415 | } else { | 446 | } else { |
| 416 | fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type); | 447 | fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type); |
| 448 | |||
| 449 | for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) { | ||
| 450 | FnExport *fn_export = &fn_table_entry->export_list.items[i]; | ||
| 451 | LLVMAddAlias(g->module, LLVMTypeOf(fn_table_entry->llvm_value), | ||
| 452 | fn_table_entry->llvm_value, buf_ptr(&fn_export->name)); | ||
| 453 | } | ||
| 417 | } | 454 | } |
| 418 | fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value); | 455 | fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value); |
| 419 | 456 | ||
| ... | @@ -441,20 +478,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { | ... | @@ -441,20 +478,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 441 | } | 478 | } |
| 442 | } | 479 | } |
| 443 | 480 | ||
| 444 | switch (fn_table_entry->linkage) { | 481 | LLVMSetLinkage(fn_table_entry->llvm_value, to_llvm_linkage(linkage)); |
| 445 | case GlobalLinkageIdInternal: | 482 | |
| 446 | LLVMSetLinkage(fn_table_entry->llvm_value, LLVMInternalLinkage); | 483 | if (linkage == GlobalLinkageIdInternal) { |
| 447 | LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true); | 484 | LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true); |
| 448 | break; | ||
| 449 | case GlobalLinkageIdStrong: | ||
| 450 | LLVMSetLinkage(fn_table_entry->llvm_value, LLVMExternalLinkage); | ||
| 451 | break; | ||
| 452 | case GlobalLinkageIdWeak: | ||
| 453 | LLVMSetLinkage(fn_table_entry->llvm_value, LLVMWeakODRLinkage); | ||
| 454 | break; | ||
| 455 | case GlobalLinkageIdLinkOnce: | ||
| 456 | LLVMSetLinkage(fn_table_entry->llvm_value, LLVMLinkOnceODRLinkage); | ||
| 457 | break; | ||
| 458 | } | 485 | } |
| 459 | 486 | ||
| 460 | if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { | 487 | if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { |
| ... | @@ -561,7 +588,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { | ... | @@ -561,7 +588,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 561 | bool is_definition = fn_table_entry->body_node != nullptr; | 588 | bool is_definition = fn_table_entry->body_node != nullptr; |
| 562 | unsigned flags = 0; | 589 | unsigned flags = 0; |
| 563 | bool is_optimized = g->build_mode != BuildModeDebug; | 590 | bool is_optimized = g->build_mode != BuildModeDebug; |
| 564 | bool is_internal_linkage = (fn_table_entry->linkage == GlobalLinkageIdInternal); | 591 | bool is_internal_linkage = (fn_table_entry->body_node != nullptr && |
| 592 | fn_table_entry->export_list.length == 0); | ||
| 565 | ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, | 593 | ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, |
| 566 | get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "", | 594 | get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "", |
| 567 | import->di_file, line_number, | 595 | import->di_file, line_number, |
| ... | @@ -839,7 +867,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { | ... | @@ -839,7 +867,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { |
| 839 | assert(g->panic_fn != nullptr); | 867 | assert(g->panic_fn != nullptr); |
| 840 | LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn); | 868 | LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn); |
| 841 | LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc); | 869 | LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc); |
| 842 | ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, false, ""); | 870 | ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, ZigLLVM_FnInlineAuto, ""); |
| 843 | LLVMBuildUnreachable(g->builder); | 871 | LLVMBuildUnreachable(g->builder); |
| 844 | } | 872 | } |
| 845 | 873 | ||
| ... | @@ -988,7 +1016,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { | ... | @@ -988,7 +1016,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 988 | static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { | 1016 | static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { |
| 989 | LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); | 1017 | LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); |
| 990 | ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified), | 1018 | ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified), |
| 991 | false, ""); | 1019 | ZigLLVM_FnInlineAuto, ""); |
| 992 | LLVMBuildUnreachable(g->builder); | 1020 | LLVMBuildUnreachable(g->builder); |
| 993 | } | 1021 | } |
| 994 | 1022 | ||
| ... | @@ -1210,11 +1238,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry | ... | @@ -1210,11 +1238,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry |
| 1210 | return nullptr; | 1238 | return nullptr; |
| 1211 | } | 1239 | } |
| 1212 | 1240 | ||
| 1241 | bool big_endian = g->is_big_endian; | ||
| 1242 | |||
| 1213 | LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, ""); | 1243 | LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, ""); |
| 1214 | 1244 | ||
| 1215 | uint32_t bit_offset = ptr_type->data.pointer.bit_offset; | 1245 | uint32_t bit_offset = ptr_type->data.pointer.bit_offset; |
| 1216 | uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); | 1246 | uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); |
| 1217 | uint32_t shift_amt = host_bit_count - bit_offset - unaligned_bit_count; | 1247 | uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - unaligned_bit_count : bit_offset; |
| 1218 | LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false); | 1248 | LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false); |
| 1219 | 1249 | ||
| 1220 | LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref); | 1250 | LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref); |
| ... | @@ -2170,12 +2200,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI | ... | @@ -2170,12 +2200,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 2170 | if (unaligned_bit_count == 0) | 2200 | if (unaligned_bit_count == 0) |
| 2171 | return get_handle_value(g, ptr, child_type, ptr_type); | 2201 | return get_handle_value(g, ptr, child_type, ptr_type); |
| 2172 | 2202 | ||
| 2203 | bool big_endian = g->is_big_endian; | ||
| 2204 | |||
| 2173 | assert(!handle_is_ptr(child_type)); | 2205 | assert(!handle_is_ptr(child_type)); |
| 2174 | LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, ""); | 2206 | LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, ""); |
| 2175 | 2207 | ||
| 2176 | uint32_t bit_offset = ptr_type->data.pointer.bit_offset; | 2208 | uint32_t bit_offset = ptr_type->data.pointer.bit_offset; |
| 2177 | uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); | 2209 | uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); |
| 2178 | uint32_t shift_amt = host_bit_count - bit_offset - unaligned_bit_count; | 2210 | uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - unaligned_bit_count : bit_offset; |
| 2179 | 2211 | ||
| 2180 | LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false); | 2212 | LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false); |
| 2181 | LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, ""); | 2213 | LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, ""); |
| ... | @@ -2316,12 +2348,22 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -2316,12 +2348,22 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2316 | } | 2348 | } |
| 2317 | } | 2349 | } |
| 2318 | 2350 | ||
| 2319 | bool want_always_inline = (instruction->fn_entry != nullptr && | 2351 | ZigLLVM_FnInline fn_inline; |
| 2320 | instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_inline; | 2352 | switch (instruction->fn_inline) { |
| 2353 | case FnInlineAuto: | ||
| 2354 | fn_inline = ZigLLVM_FnInlineAuto; | ||
| 2355 | break; | ||
| 2356 | case FnInlineAlways: | ||
| 2357 | fn_inline = (instruction->fn_entry == nullptr) ? ZigLLVM_FnInlineAuto : ZigLLVM_FnInlineAlways; | ||
| 2358 | break; | ||
| 2359 | case FnInlineNever: | ||
| 2360 | fn_inline = ZigLLVM_FnInlineNever; | ||
| 2361 | break; | ||
| 2362 | } | ||
| 2321 | 2363 | ||
| 2322 | LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc); | 2364 | LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc); |
| 2323 | LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val, | 2365 | LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val, |
| 2324 | gen_param_values, (unsigned)gen_param_index, llvm_cc, want_always_inline, ""); | 2366 | gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, ""); |
| 2325 | 2367 | ||
| 2326 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { | 2368 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { |
| 2327 | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; | 2369 | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; |
| ... | @@ -2684,6 +2726,9 @@ static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstru | ... | @@ -2684,6 +2726,9 @@ static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstru |
| 2684 | } | 2726 | } |
| 2685 | 2727 | ||
| 2686 | static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRef *instruction) { | 2728 | static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRef *instruction) { |
| 2729 | if (!type_has_bits(instruction->base.value.type)) { | ||
| 2730 | return nullptr; | ||
| 2731 | } | ||
| 2687 | LLVMValueRef value = ir_llvm_value(g, instruction->value); | 2732 | LLVMValueRef value = ir_llvm_value(g, instruction->value); |
| 2688 | if (handle_is_ptr(instruction->value->value.type)) { | 2733 | if (handle_is_ptr(instruction->value->value.type)) { |
| 2689 | return value; | 2734 | return value; |
| ... | @@ -2975,6 +3020,15 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst | ... | @@ -2975,6 +3020,15 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst |
| 2975 | add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); | 3020 | add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); |
| 2976 | } | 3021 | } |
| 2977 | } | 3022 | } |
| 3023 | if (!type_has_bits(array_type)) { | ||
| 3024 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); | ||
| 3025 | |||
| 3026 | // TODO if debug safety is on, store 0xaaaaaaa in ptr field | ||
| 3027 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | ||
| 3028 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | ||
| 3029 | return tmp_struct_ptr; | ||
| 3030 | } | ||
| 3031 | |||
| 2978 | 3032 | ||
| 2979 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); | 3033 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); |
| 2980 | LLVMValueRef indices[] = { | 3034 | LLVMValueRef indices[] = { |
| ... | @@ -3473,8 +3527,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -3473,8 +3527,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3473 | case IrInstructionIdCheckStatementIsVoid: | 3527 | case IrInstructionIdCheckStatementIsVoid: |
| 3474 | case IrInstructionIdTypeName: | 3528 | case IrInstructionIdTypeName: |
| 3475 | case IrInstructionIdCanImplicitCast: | 3529 | case IrInstructionIdCanImplicitCast: |
| 3476 | case IrInstructionIdSetGlobalSection: | ||
| 3477 | case IrInstructionIdSetGlobalLinkage: | ||
| 3478 | case IrInstructionIdDeclRef: | 3530 | case IrInstructionIdDeclRef: |
| 3479 | case IrInstructionIdSwitchVar: | 3531 | case IrInstructionIdSwitchVar: |
| 3480 | case IrInstructionIdOffsetOf: | 3532 | case IrInstructionIdOffsetOf: |
| ... | @@ -3485,6 +3537,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -3485,6 +3537,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3485 | case IrInstructionIdSetAlignStack: | 3537 | case IrInstructionIdSetAlignStack: |
| 3486 | case IrInstructionIdArgType: | 3538 | case IrInstructionIdArgType: |
| 3487 | case IrInstructionIdTagType: | 3539 | case IrInstructionIdTagType: |
| 3540 | case IrInstructionIdExport: | ||
| 3488 | zig_unreachable(); | 3541 | zig_unreachable(); |
| 3489 | case IrInstructionIdReturn: | 3542 | case IrInstructionIdReturn: |
| 3490 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); | 3543 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| ... | @@ -3747,17 +3800,26 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con | ... | @@ -3747,17 +3800,26 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con |
| 3747 | case TypeTableEntryIdStruct: | 3800 | case TypeTableEntryIdStruct: |
| 3748 | { | 3801 | { |
| 3749 | assert(type_entry->data.structure.layout == ContainerLayoutPacked); | 3802 | assert(type_entry->data.structure.layout == ContainerLayoutPacked); |
| 3803 | bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type | ||
| 3750 | 3804 | ||
| 3751 | LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); | 3805 | LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); |
| 3806 | size_t used_bits = 0; | ||
| 3752 | for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { | 3807 | for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { |
| 3753 | TypeStructField *field = &type_entry->data.structure.fields[i]; | 3808 | TypeStructField *field = &type_entry->data.structure.fields[i]; |
| 3754 | if (field->gen_index == SIZE_MAX) { | 3809 | if (field->gen_index == SIZE_MAX) { |
| 3755 | continue; | 3810 | continue; |
| 3756 | } | 3811 | } |
| 3757 | LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, &const_val->data.x_struct.fields[i]); | 3812 | LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, &const_val->data.x_struct.fields[i]); |
| 3758 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, field->packed_bits_size, false); | 3813 | if (is_big_endian) { |
| 3759 | val = LLVMConstShl(val, shift_amt); | 3814 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, field->packed_bits_size, false); |
| 3760 | val = LLVMConstOr(val, child_val); | 3815 | val = LLVMConstShl(val, shift_amt); |
| 3816 | val = LLVMConstOr(val, child_val); | ||
| 3817 | } else { | ||
| 3818 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); | ||
| 3819 | LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); | ||
| 3820 | val = LLVMConstOr(val, child_val_shifted); | ||
| 3821 | used_bits += field->packed_bits_size; | ||
| 3822 | } | ||
| 3761 | } | 3823 | } |
| 3762 | return val; | 3824 | return val; |
| 3763 | } | 3825 | } |
| ... | @@ -3882,9 +3944,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3882,9 +3944,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3882 | fields[type_struct_field->gen_index] = val; | 3944 | fields[type_struct_field->gen_index] = val; |
| 3883 | make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val); | 3945 | make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val); |
| 3884 | } else { | 3946 | } else { |
| 3947 | bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type | ||
| 3885 | LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref, | 3948 | LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref, |
| 3886 | (unsigned)type_struct_field->gen_index); | 3949 | (unsigned)type_struct_field->gen_index); |
| 3887 | LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); | 3950 | LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); |
| 3951 | size_t used_bits = 0; | ||
| 3888 | for (size_t i = src_field_index; i < src_field_index_end; i += 1) { | 3952 | for (size_t i = src_field_index; i < src_field_index_end; i += 1) { |
| 3889 | TypeStructField *it_field = &type_entry->data.structure.fields[i]; | 3953 | TypeStructField *it_field = &type_entry->data.structure.fields[i]; |
| 3890 | if (it_field->gen_index == SIZE_MAX) { | 3954 | if (it_field->gen_index == SIZE_MAX) { |
| ... | @@ -3892,10 +3956,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3892,10 +3956,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3892 | } | 3956 | } |
| 3893 | LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, | 3957 | LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, |
| 3894 | &const_val->data.x_struct.fields[i]); | 3958 | &const_val->data.x_struct.fields[i]); |
| 3895 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, | 3959 | if (is_big_endian) { |
| 3896 | it_field->packed_bits_size, false); | 3960 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, |
| 3897 | val = LLVMConstShl(val, shift_amt); | 3961 | it_field->packed_bits_size, false); |
| 3898 | val = LLVMConstOr(val, child_val); | 3962 | val = LLVMConstShl(val, shift_amt); |
| 3963 | val = LLVMConstOr(val, child_val); | ||
| 3964 | } else { | ||
| 3965 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); | ||
| 3966 | LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); | ||
| 3967 | val = LLVMConstOr(val, child_val_shifted); | ||
| 3968 | used_bits += it_field->packed_bits_size; | ||
| 3969 | } | ||
| 3899 | } | 3970 | } |
| 3900 | fields[type_struct_field->gen_index] = val; | 3971 | fields[type_struct_field->gen_index] = val; |
| 3901 | } | 3972 | } |
| ... | @@ -3946,8 +4017,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3946,8 +4017,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3946 | case TypeTableEntryIdUnion: | 4017 | case TypeTableEntryIdUnion: |
| 3947 | { | 4018 | { |
| 3948 | LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; | 4019 | LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; |
| 3949 | ConstExprValue *payload_value = const_val->data.x_union.payload; | ||
| 3950 | assert(payload_value != nullptr); | ||
| 3951 | 4020 | ||
| 3952 | if (type_entry->data.unionation.gen_field_count == 0) { | 4021 | if (type_entry->data.unionation.gen_field_count == 0) { |
| 3953 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { | 4022 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { |
| ... | @@ -3960,7 +4029,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3960,7 +4029,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3960 | 4029 | ||
| 3961 | LLVMValueRef union_value_ref; | 4030 | LLVMValueRef union_value_ref; |
| 3962 | bool make_unnamed_struct; | 4031 | bool make_unnamed_struct; |
| 3963 | if (!type_has_bits(payload_value->type)) { | 4032 | ConstExprValue *payload_value = const_val->data.x_union.payload; |
| 4033 | if (payload_value == nullptr || !type_has_bits(payload_value->type)) { | ||
| 3964 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) | 4034 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) |
| 3965 | return LLVMGetUndef(type_entry->type_ref); | 4035 | return LLVMGetUndef(type_entry->type_ref); |
| 3966 | 4036 | ||
| ... | @@ -4635,6 +4705,7 @@ static const uint8_t int_sizes_in_bits[] = { | ... | @@ -4635,6 +4705,7 @@ static const uint8_t int_sizes_in_bits[] = { |
| 4635 | 7, | 4705 | 7, |
| 4636 | 8, | 4706 | 8, |
| 4637 | 16, | 4707 | 16, |
| 4708 | 29, | ||
| 4638 | 32, | 4709 | 32, |
| 4639 | 64, | 4710 | 64, |
| 4640 | 128, | 4711 | 128, |
| ... | @@ -4955,8 +5026,6 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -4955,8 +5026,6 @@ static void define_builtin_fns(CodeGen *g) { |
| 4955 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int | 5026 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int |
| 4956 | create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); | 5027 | create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); |
| 4957 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2); | 5028 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2); |
| 4958 | create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); | ||
| 4959 | create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2); | ||
| 4960 | create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); | 5029 | create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); |
| 4961 | create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2); | 5030 | create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2); |
| 4962 | create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2); | 5031 | create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2); |
| ... | @@ -4972,6 +5041,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -4972,6 +5041,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4972 | create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); | 5041 | create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); |
| 4973 | create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); | 5042 | create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); |
| 4974 | create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); | 5043 | create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); |
| 5044 | create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX); | ||
| 4975 | create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1); | 5045 | create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1); |
| 4976 | create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2); | 5046 | create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2); |
| 4977 | create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2); | 5047 | create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2); |
| ... | @@ -4980,6 +5050,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -4980,6 +5050,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4980 | create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); | 5050 | create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); |
| 4981 | create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); | 5051 | create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); |
| 4982 | create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); | 5052 | create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); |
| 5053 | create_builtin_fn(g, BuiltinFnIdExport, "export", 3); | ||
| 4983 | } | 5054 | } |
| 4984 | 5055 | ||
| 4985 | static const char *bool_to_str(bool b) { | 5056 | static const char *bool_to_str(bool b) { |
| ... | @@ -5298,18 +5369,19 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) { | ... | @@ -5298,18 +5369,19 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) { |
| 5298 | 5369 | ||
| 5299 | ZigList<ErrorMsg *> errors = {0}; | 5370 | ZigList<ErrorMsg *> errors = {0}; |
| 5300 | int err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr); | 5371 | int err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr); |
| 5301 | if (err) { | ||
| 5302 | fprintf(stderr, "unable to parse C file: %s\n", err_str(err)); | ||
| 5303 | exit(1); | ||
| 5304 | } | ||
| 5305 | 5372 | ||
| 5306 | if (errors.length > 0) { | 5373 | if (err == ErrorCCompileErrors && errors.length > 0) { |
| 5307 | for (size_t i = 0; i < errors.length; i += 1) { | 5374 | for (size_t i = 0; i < errors.length; i += 1) { |
| 5308 | ErrorMsg *err_msg = errors.at(i); | 5375 | ErrorMsg *err_msg = errors.at(i); |
| 5309 | print_err_msg(err_msg, g->err_color); | 5376 | print_err_msg(err_msg, g->err_color); |
| 5310 | } | 5377 | } |
| 5311 | exit(1); | 5378 | exit(1); |
| 5312 | } | 5379 | } |
| 5380 | |||
| 5381 | if (err) { | ||
| 5382 | fprintf(stderr, "unable to parse C file: %s\n", err_str(err)); | ||
| 5383 | exit(1); | ||
| 5384 | } | ||
| 5313 | } | 5385 | } |
| 5314 | 5386 | ||
| 5315 | static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) { | 5387 | static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) { |
| ... | @@ -5417,6 +5489,27 @@ static void gen_root_source(CodeGen *g) { | ... | @@ -5417,6 +5489,27 @@ static void gen_root_source(CodeGen *g) { |
| 5417 | assert(g->root_out_name); | 5489 | assert(g->root_out_name); |
| 5418 | assert(g->out_type != OutTypeUnknown); | 5490 | assert(g->out_type != OutTypeUnknown); |
| 5419 | 5491 | ||
| 5492 | { | ||
| 5493 | // Zig has lazy top level definitions. Here we semantically analyze the panic function. | ||
| 5494 | ImportTableEntry *import_with_panic; | ||
| 5495 | if (g->have_pub_panic) { | ||
| 5496 | import_with_panic = g->root_import; | ||
| 5497 | } else { | ||
| 5498 | g->panic_package = create_panic_pkg(g); | ||
| 5499 | import_with_panic = add_special_code(g, g->panic_package, "panic.zig"); | ||
| 5500 | } | ||
| 5501 | scan_import(g, import_with_panic); | ||
| 5502 | Tld *panic_tld = find_decl(g, &import_with_panic->decls_scope->base, buf_create_from_str("panic")); | ||
| 5503 | assert(panic_tld != nullptr); | ||
| 5504 | resolve_top_level_decl(g, panic_tld, false, nullptr); | ||
| 5505 | } | ||
| 5506 | |||
| 5507 | |||
| 5508 | if (!g->error_during_imports) { | ||
| 5509 | semantic_analyze(g); | ||
| 5510 | } | ||
| 5511 | report_errors_and_maybe_exit(g); | ||
| 5512 | |||
| 5420 | if (!g->is_test_build && g->zig_target.os != ZigLLVM_UnknownOS && | 5513 | if (!g->is_test_build && g->zig_target.os != ZigLLVM_UnknownOS && |
| 5421 | !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && | 5514 | !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && |
| 5422 | ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) | 5515 | ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) |
| ... | @@ -5426,20 +5519,6 @@ static void gen_root_source(CodeGen *g) { | ... | @@ -5426,20 +5519,6 @@ static void gen_root_source(CodeGen *g) { |
| 5426 | if (g->zig_target.os == ZigLLVM_Win32 && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib) { | 5519 | if (g->zig_target.os == ZigLLVM_Win32 && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib) { |
| 5427 | g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); | 5520 | g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); |
| 5428 | } | 5521 | } |
| 5429 | ImportTableEntry *import_with_panic; | ||
| 5430 | if (g->have_pub_panic) { | ||
| 5431 | import_with_panic = g->root_import; | ||
| 5432 | } else { | ||
| 5433 | g->panic_package = create_panic_pkg(g); | ||
| 5434 | import_with_panic = add_special_code(g, g->panic_package, "panic.zig"); | ||
| 5435 | } | ||
| 5436 | // Zig has lazy top level definitions. Here we semantically analyze the panic function. | ||
| 5437 | { | ||
| 5438 | scan_import(g, import_with_panic); | ||
| 5439 | Tld *panic_tld = find_decl(g, &import_with_panic->decls_scope->base, buf_create_from_str("panic")); | ||
| 5440 | assert(panic_tld != nullptr); | ||
| 5441 | resolve_top_level_decl(g, panic_tld, false, nullptr); | ||
| 5442 | } | ||
| 5443 | 5522 | ||
| 5444 | if (!g->error_during_imports) { | 5523 | if (!g->error_during_imports) { |
| 5445 | semantic_analyze(g); | 5524 | semantic_analyze(g); |
| ... | @@ -5666,7 +5745,7 @@ static void gen_h_file(CodeGen *g) { | ... | @@ -5666,7 +5745,7 @@ static void gen_h_file(CodeGen *g) { |
| 5666 | for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { | 5745 | for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { |
| 5667 | FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i); | 5746 | FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i); |
| 5668 | 5747 | ||
| 5669 | if (fn_table_entry->linkage == GlobalLinkageIdInternal) | 5748 | if (fn_table_entry->export_list.length == 0) |
| 5670 | continue; | 5749 | continue; |
| 5671 | 5750 | ||
| 5672 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; | 5751 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; |
src/ir.cpp+632-445| ... | @@ -207,6 +207,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { | ... | @@ -207,6 +207,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { |
| 207 | return IrInstructionIdDeclVar; | 207 | return IrInstructionIdDeclVar; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) { | ||
| 211 | return IrInstructionIdExport; | ||
| 212 | } | ||
| 213 | |||
| 210 | static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) { | 214 | static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) { |
| 211 | return IrInstructionIdLoadPtr; | 215 | return IrInstructionIdLoadPtr; |
| 212 | } | 216 | } |
| ... | @@ -523,14 +527,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast | ... | @@ -523,14 +527,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast |
| 523 | return IrInstructionIdCanImplicitCast; | 527 | return IrInstructionIdCanImplicitCast; |
| 524 | } | 528 | } |
| 525 | 529 | ||
| 526 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection *) { | ||
| 527 | return IrInstructionIdSetGlobalSection; | ||
| 528 | } | ||
| 529 | |||
| 530 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalLinkage *) { | ||
| 531 | return IrInstructionIdSetGlobalLinkage; | ||
| 532 | } | ||
| 533 | |||
| 534 | static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) { | 530 | static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) { |
| 535 | return IrInstructionIdDeclRef; | 531 | return IrInstructionIdDeclRef; |
| 536 | } | 532 | } |
| ... | @@ -928,13 +924,13 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio | ... | @@ -928,13 +924,13 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio |
| 928 | 924 | ||
| 929 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, | 925 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 930 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, | 926 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 931 | bool is_comptime, bool is_inline) | 927 | bool is_comptime, FnInline fn_inline) |
| 932 | { | 928 | { |
| 933 | IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node); | 929 | IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node); |
| 934 | call_instruction->fn_entry = fn_entry; | 930 | call_instruction->fn_entry = fn_entry; |
| 935 | call_instruction->fn_ref = fn_ref; | 931 | call_instruction->fn_ref = fn_ref; |
| 936 | call_instruction->is_comptime = is_comptime; | 932 | call_instruction->is_comptime = is_comptime; |
| 937 | call_instruction->is_inline = is_inline; | 933 | call_instruction->fn_inline = fn_inline; |
| 938 | call_instruction->args = args; | 934 | call_instruction->args = args; |
| 939 | call_instruction->arg_count = arg_count; | 935 | call_instruction->arg_count = arg_count; |
| 940 | 936 | ||
| ... | @@ -948,10 +944,10 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc | ... | @@ -948,10 +944,10 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc |
| 948 | 944 | ||
| 949 | static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, | 945 | static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, |
| 950 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, | 946 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 951 | bool is_comptime, bool is_inline) | 947 | bool is_comptime, FnInline fn_inline) |
| 952 | { | 948 | { |
| 953 | IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope, | 949 | IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope, |
| 954 | old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, is_inline); | 950 | old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline); |
| 955 | ir_link_new_instruction(new_instruction, old_instruction); | 951 | ir_link_new_instruction(new_instruction, old_instruction); |
| 956 | return new_instruction; | 952 | return new_instruction; |
| 957 | } | 953 | } |
| ... | @@ -1025,7 +1021,7 @@ static IrInstruction *ir_build_ptr_type_of(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -1025,7 +1021,7 @@ static IrInstruction *ir_build_ptr_type_of(IrBuilder *irb, Scope *scope, AstNode |
| 1025 | ptr_type_of_instruction->bit_offset_start = bit_offset_start; | 1021 | ptr_type_of_instruction->bit_offset_start = bit_offset_start; |
| 1026 | ptr_type_of_instruction->bit_offset_end = bit_offset_end; | 1022 | ptr_type_of_instruction->bit_offset_end = bit_offset_end; |
| 1027 | 1023 | ||
| 1028 | ir_ref_instruction(align_value, irb->current_basic_block); | 1024 | if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); |
| 1029 | ir_ref_instruction(child_type, irb->current_basic_block); | 1025 | ir_ref_instruction(child_type, irb->current_basic_block); |
| 1030 | 1026 | ||
| 1031 | return &ptr_type_of_instruction->base; | 1027 | return &ptr_type_of_instruction->base; |
| ... | @@ -1191,6 +1187,8 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s | ... | @@ -1191,6 +1187,8 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s |
| 1191 | if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); | 1187 | if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); |
| 1192 | ir_ref_instruction(init_value, irb->current_basic_block); | 1188 | ir_ref_instruction(init_value, irb->current_basic_block); |
| 1193 | 1189 | ||
| 1190 | var->decl_instruction = &decl_var_instruction->base; | ||
| 1191 | |||
| 1194 | return &decl_var_instruction->base; | 1192 | return &decl_var_instruction->base; |
| 1195 | } | 1193 | } |
| 1196 | 1194 | ||
| ... | @@ -1203,6 +1201,24 @@ static IrInstruction *ir_build_var_decl_from(IrBuilder *irb, IrInstruction *old_ | ... | @@ -1203,6 +1201,24 @@ static IrInstruction *ir_build_var_decl_from(IrBuilder *irb, IrInstruction *old_ |
| 1203 | return new_instruction; | 1201 | return new_instruction; |
| 1204 | } | 1202 | } |
| 1205 | 1203 | ||
| 1204 | static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 1205 | IrInstruction *name, IrInstruction *target, IrInstruction *linkage) | ||
| 1206 | { | ||
| 1207 | IrInstructionExport *export_instruction = ir_build_instruction<IrInstructionExport>( | ||
| 1208 | irb, scope, source_node); | ||
| 1209 | export_instruction->base.value.special = ConstValSpecialStatic; | ||
| 1210 | export_instruction->base.value.type = irb->codegen->builtin_types.entry_void; | ||
| 1211 | export_instruction->name = name; | ||
| 1212 | export_instruction->target = target; | ||
| 1213 | export_instruction->linkage = linkage; | ||
| 1214 | |||
| 1215 | ir_ref_instruction(name, irb->current_basic_block); | ||
| 1216 | ir_ref_instruction(target, irb->current_basic_block); | ||
| 1217 | if (linkage) ir_ref_instruction(linkage, irb->current_basic_block); | ||
| 1218 | |||
| 1219 | return &export_instruction->base; | ||
| 1220 | } | ||
| 1221 | |||
| 1206 | static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { | 1222 | static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { |
| 1207 | IrInstructionLoadPtr *instruction = ir_build_instruction<IrInstructionLoadPtr>(irb, scope, source_node); | 1223 | IrInstructionLoadPtr *instruction = ir_build_instruction<IrInstructionLoadPtr>(irb, scope, source_node); |
| 1208 | instruction->ptr = ptr; | 1224 | instruction->ptr = ptr; |
| ... | @@ -2157,32 +2173,6 @@ static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, A | ... | @@ -2157,32 +2173,6 @@ static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, A |
| 2157 | return &instruction->base; | 2173 | return &instruction->base; |
| 2158 | } | 2174 | } |
| 2159 | 2175 | ||
| 2160 | static IrInstruction *ir_build_set_global_section(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2161 | Tld *tld, IrInstruction *value) | ||
| 2162 | { | ||
| 2163 | IrInstructionSetGlobalSection *instruction = ir_build_instruction<IrInstructionSetGlobalSection>( | ||
| 2164 | irb, scope, source_node); | ||
| 2165 | instruction->tld = tld; | ||
| 2166 | instruction->value = value; | ||
| 2167 | |||
| 2168 | ir_ref_instruction(value, irb->current_basic_block); | ||
| 2169 | |||
| 2170 | return &instruction->base; | ||
| 2171 | } | ||
| 2172 | |||
| 2173 | static IrInstruction *ir_build_set_global_linkage(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2174 | Tld *tld, IrInstruction *value) | ||
| 2175 | { | ||
| 2176 | IrInstructionSetGlobalLinkage *instruction = ir_build_instruction<IrInstructionSetGlobalLinkage>( | ||
| 2177 | irb, scope, source_node); | ||
| 2178 | instruction->tld = tld; | ||
| 2179 | instruction->value = value; | ||
| 2180 | |||
| 2181 | ir_ref_instruction(value, irb->current_basic_block); | ||
| 2182 | |||
| 2183 | return &instruction->base; | ||
| 2184 | } | ||
| 2185 | |||
| 2186 | static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2176 | static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2187 | Tld *tld, LVal lval) | 2177 | Tld *tld, LVal lval) |
| 2188 | { | 2178 | { |
| ... | @@ -2394,6 +2384,21 @@ static IrInstruction *ir_instruction_declvar_get_dep(IrInstructionDeclVar *instr | ... | @@ -2394,6 +2384,21 @@ static IrInstruction *ir_instruction_declvar_get_dep(IrInstructionDeclVar *instr |
| 2394 | return nullptr; | 2384 | return nullptr; |
| 2395 | } | 2385 | } |
| 2396 | 2386 | ||
| 2387 | static IrInstruction *ir_instruction_export_get_dep(IrInstructionExport *instruction, size_t index) { | ||
| 2388 | if (index < 1) return instruction->name; | ||
| 2389 | index -= 1; | ||
| 2390 | |||
| 2391 | if (index < 1) return instruction->target; | ||
| 2392 | index -= 1; | ||
| 2393 | |||
| 2394 | if (instruction->linkage != nullptr) { | ||
| 2395 | if (index < 1) return instruction->linkage; | ||
| 2396 | index -= 1; | ||
| 2397 | } | ||
| 2398 | |||
| 2399 | return nullptr; | ||
| 2400 | } | ||
| 2401 | |||
| 2397 | static IrInstruction *ir_instruction_loadptr_get_dep(IrInstructionLoadPtr *instruction, size_t index) { | 2402 | static IrInstruction *ir_instruction_loadptr_get_dep(IrInstructionLoadPtr *instruction, size_t index) { |
| 2398 | switch (index) { | 2403 | switch (index) { |
| 2399 | case 0: return instruction->ptr; | 2404 | case 0: return instruction->ptr; |
| ... | @@ -2977,20 +2982,6 @@ static IrInstruction *ir_instruction_canimplicitcast_get_dep(IrInstructionCanImp | ... | @@ -2977,20 +2982,6 @@ static IrInstruction *ir_instruction_canimplicitcast_get_dep(IrInstructionCanImp |
| 2977 | } | 2982 | } |
| 2978 | } | 2983 | } |
| 2979 | 2984 | ||
| 2980 | static IrInstruction *ir_instruction_setglobalsection_get_dep(IrInstructionSetGlobalSection *instruction, size_t index) { | ||
| 2981 | switch (index) { | ||
| 2982 | case 0: return instruction->value; | ||
| 2983 | default: return nullptr; | ||
| 2984 | } | ||
| 2985 | } | ||
| 2986 | |||
| 2987 | static IrInstruction *ir_instruction_setgloballinkage_get_dep(IrInstructionSetGlobalLinkage *instruction, size_t index) { | ||
| 2988 | switch (index) { | ||
| 2989 | case 0: return instruction->value; | ||
| 2990 | default: return nullptr; | ||
| 2991 | } | ||
| 2992 | } | ||
| 2993 | |||
| 2994 | static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) { | 2985 | static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) { |
| 2995 | return nullptr; | 2986 | return nullptr; |
| 2996 | } | 2987 | } |
| ... | @@ -3104,6 +3095,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t | ... | @@ -3104,6 +3095,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3104 | return ir_instruction_binop_get_dep((IrInstructionBinOp *) instruction, index); | 3095 | return ir_instruction_binop_get_dep((IrInstructionBinOp *) instruction, index); |
| 3105 | case IrInstructionIdDeclVar: | 3096 | case IrInstructionIdDeclVar: |
| 3106 | return ir_instruction_declvar_get_dep((IrInstructionDeclVar *) instruction, index); | 3097 | return ir_instruction_declvar_get_dep((IrInstructionDeclVar *) instruction, index); |
| 3098 | case IrInstructionIdExport: | ||
| 3099 | return ir_instruction_export_get_dep((IrInstructionExport *) instruction, index); | ||
| 3107 | case IrInstructionIdLoadPtr: | 3100 | case IrInstructionIdLoadPtr: |
| 3108 | return ir_instruction_loadptr_get_dep((IrInstructionLoadPtr *) instruction, index); | 3101 | return ir_instruction_loadptr_get_dep((IrInstructionLoadPtr *) instruction, index); |
| 3109 | case IrInstructionIdStorePtr: | 3102 | case IrInstructionIdStorePtr: |
| ... | @@ -3262,10 +3255,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t | ... | @@ -3262,10 +3255,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3262 | return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index); | 3255 | return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index); |
| 3263 | case IrInstructionIdCanImplicitCast: | 3256 | case IrInstructionIdCanImplicitCast: |
| 3264 | return ir_instruction_canimplicitcast_get_dep((IrInstructionCanImplicitCast *) instruction, index); | 3257 | return ir_instruction_canimplicitcast_get_dep((IrInstructionCanImplicitCast *) instruction, index); |
| 3265 | case IrInstructionIdSetGlobalSection: | ||
| 3266 | return ir_instruction_setglobalsection_get_dep((IrInstructionSetGlobalSection *) instruction, index); | ||
| 3267 | case IrInstructionIdSetGlobalLinkage: | ||
| 3268 | return ir_instruction_setgloballinkage_get_dep((IrInstructionSetGlobalLinkage *) instruction, index); | ||
| 3269 | case IrInstructionIdDeclRef: | 3258 | case IrInstructionIdDeclRef: |
| 3270 | return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index); | 3259 | return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index); |
| 3271 | case IrInstructionIdPanic: | 3260 | case IrInstructionIdPanic: |
| ... | @@ -3522,33 +3511,14 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s | ... | @@ -3522,33 +3511,14 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s |
| 3522 | return var; | 3511 | return var; |
| 3523 | } | 3512 | } |
| 3524 | 3513 | ||
| 3525 | static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name) { | ||
| 3526 | while (scope) { | ||
| 3527 | if (scope->id == ScopeIdBlock) { | ||
| 3528 | ScopeBlock *block_scope = (ScopeBlock *)scope; | ||
| 3529 | auto entry = block_scope->label_table.maybe_get(name); | ||
| 3530 | if (entry) | ||
| 3531 | return entry->value; | ||
| 3532 | } | ||
| 3533 | scope = scope->parent; | ||
| 3534 | } | ||
| 3535 | |||
| 3536 | return nullptr; | ||
| 3537 | } | ||
| 3538 | |||
| 3539 | static ScopeBlock *find_block_scope(IrExecutable *exec, Scope *scope) { | ||
| 3540 | while (scope) { | ||
| 3541 | if (scope->id == ScopeIdBlock) | ||
| 3542 | return (ScopeBlock *)scope; | ||
| 3543 | scope = scope->parent; | ||
| 3544 | } | ||
| 3545 | return nullptr; | ||
| 3546 | } | ||
| 3547 | |||
| 3548 | static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) { | 3514 | static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) { |
| 3549 | assert(block_node->type == NodeTypeBlock); | 3515 | assert(block_node->type == NodeTypeBlock); |
| 3550 | 3516 | ||
| 3517 | ZigList<IrInstruction *> incoming_values = {0}; | ||
| 3518 | ZigList<IrBasicBlock *> incoming_blocks = {0}; | ||
| 3519 | |||
| 3551 | ScopeBlock *scope_block = create_block_scope(block_node, parent_scope); | 3520 | ScopeBlock *scope_block = create_block_scope(block_node, parent_scope); |
| 3521 | |||
| 3552 | Scope *outer_block_scope = &scope_block->base; | 3522 | Scope *outer_block_scope = &scope_block->base; |
| 3553 | Scope *child_scope = outer_block_scope; | 3523 | Scope *child_scope = outer_block_scope; |
| 3554 | 3524 | ||
| ... | @@ -3562,44 +3532,18 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -3562,44 +3532,18 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3562 | return ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); | 3532 | return ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); |
| 3563 | } | 3533 | } |
| 3564 | 3534 | ||
| 3535 | if (block_node->data.block.name != nullptr) { | ||
| 3536 | scope_block->incoming_blocks = &incoming_blocks; | ||
| 3537 | scope_block->incoming_values = &incoming_values; | ||
| 3538 | scope_block->end_block = ir_build_basic_block(irb, parent_scope, "BlockEnd"); | ||
| 3539 | scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope)); | ||
| 3540 | } | ||
| 3541 | |||
| 3565 | bool is_continuation_unreachable = false; | 3542 | bool is_continuation_unreachable = false; |
| 3566 | IrInstruction *noreturn_return_value = nullptr; | 3543 | IrInstruction *noreturn_return_value = nullptr; |
| 3567 | IrInstruction *return_value = nullptr; | ||
| 3568 | for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { | 3544 | for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { |
| 3569 | AstNode *statement_node = block_node->data.block.statements.at(i); | 3545 | AstNode *statement_node = block_node->data.block.statements.at(i); |
| 3570 | 3546 | ||
| 3571 | if (statement_node->type == NodeTypeLabel) { | ||
| 3572 | Buf *label_name = statement_node->data.label.name; | ||
| 3573 | IrBasicBlock *label_block = ir_build_basic_block(irb, child_scope, buf_ptr(label_name)); | ||
| 3574 | LabelTableEntry *label = allocate<LabelTableEntry>(1); | ||
| 3575 | label->decl_node = statement_node; | ||
| 3576 | label->bb = label_block; | ||
| 3577 | irb->exec->all_labels.append(label); | ||
| 3578 | |||
| 3579 | LabelTableEntry *existing_label = find_label(irb->exec, child_scope, label_name); | ||
| 3580 | if (existing_label) { | ||
| 3581 | ErrorMsg *msg = add_node_error(irb->codegen, statement_node, | ||
| 3582 | buf_sprintf("duplicate label name '%s'", buf_ptr(label_name))); | ||
| 3583 | add_error_note(irb->codegen, msg, existing_label->decl_node, buf_sprintf("other label here")); | ||
| 3584 | return irb->codegen->invalid_instruction; | ||
| 3585 | } else { | ||
| 3586 | ScopeBlock *scope_block = find_block_scope(irb->exec, child_scope); | ||
| 3587 | scope_block->label_table.put(label_name, label); | ||
| 3588 | } | ||
| 3589 | |||
| 3590 | if (!is_continuation_unreachable) { | ||
| 3591 | // fall through into new labeled basic block | ||
| 3592 | IrInstruction *is_comptime = ir_mark_gen(ir_build_const_bool(irb, child_scope, statement_node, | ||
| 3593 | ir_should_inline(irb->exec, child_scope))); | ||
| 3594 | ir_mark_gen(ir_build_br(irb, child_scope, statement_node, label_block, is_comptime)); | ||
| 3595 | } | ||
| 3596 | ir_set_cursor_at_end(irb, label_block); | ||
| 3597 | |||
| 3598 | // a label is an entry point | ||
| 3599 | is_continuation_unreachable = false; | ||
| 3600 | continue; | ||
| 3601 | } | ||
| 3602 | |||
| 3603 | IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope); | 3547 | IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope); |
| 3604 | is_continuation_unreachable = instr_is_unreachable(statement_value); | 3548 | is_continuation_unreachable = instr_is_unreachable(statement_value); |
| 3605 | if (is_continuation_unreachable) { | 3549 | if (is_continuation_unreachable) { |
| ... | @@ -3614,39 +3558,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -3614,39 +3558,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3614 | // variable declarations start a new scope | 3558 | // variable declarations start a new scope |
| 3615 | IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value; | 3559 | IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value; |
| 3616 | child_scope = decl_var_instruction->var->child_scope; | 3560 | child_scope = decl_var_instruction->var->child_scope; |
| 3617 | } else { | 3561 | } else if (statement_value != irb->codegen->invalid_instruction) { |
| 3618 | // label, defer, variable declaration will never be the result expression | 3562 | // this statement's value must be void |
| 3619 | if (block_node->data.block.last_statement_is_result_expression && | 3563 | ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value)); |
| 3620 | i == block_node->data.block.statements.length - 1) { | ||
| 3621 | // this is the result value statement | ||
| 3622 | return_value = statement_value; | ||
| 3623 | } else { | ||
| 3624 | // there are more statements ahead of this one. this statement's value must be void | ||
| 3625 | if (statement_value != irb->codegen->invalid_instruction) { | ||
| 3626 | ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value)); | ||
| 3627 | } | ||
| 3628 | } | ||
| 3629 | } | 3564 | } |
| 3630 | } | 3565 | } |
| 3631 | 3566 | ||
| 3632 | if (is_continuation_unreachable) { | 3567 | if (is_continuation_unreachable) { |
| 3633 | assert(noreturn_return_value != nullptr); | 3568 | assert(noreturn_return_value != nullptr); |
| 3634 | return noreturn_return_value; | 3569 | if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) { |
| 3570 | return noreturn_return_value; | ||
| 3571 | } | ||
| 3572 | } else { | ||
| 3573 | incoming_blocks.append(irb->current_basic_block); | ||
| 3574 | incoming_values.append(ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node))); | ||
| 3635 | } | 3575 | } |
| 3636 | // control flow falls out of block | ||
| 3637 | 3576 | ||
| 3638 | if (block_node->data.block.last_statement_is_result_expression) { | 3577 | if (block_node->data.block.name != nullptr) { |
| 3639 | // return value was determined by the last statement | 3578 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); |
| 3640 | assert(return_value != nullptr); | 3579 | ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime)); |
| 3580 | ir_set_cursor_at_end(irb, scope_block->end_block); | ||
| 3581 | return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); | ||
| 3641 | } else { | 3582 | } else { |
| 3642 | // return value is implicitly void | 3583 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); |
| 3643 | assert(return_value == nullptr); | 3584 | return ir_mark_gen(ir_mark_gen(ir_build_const_void(irb, child_scope, block_node))); |
| 3644 | return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); | ||
| 3645 | } | 3585 | } |
| 3646 | |||
| 3647 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); | ||
| 3648 | |||
| 3649 | return return_value; | ||
| 3650 | } | 3586 | } |
| 3651 | 3587 | ||
| 3652 | static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) { | 3588 | static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) { |
| ... | @@ -4526,39 +4462,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4526,39 +4462,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4526 | 4462 | ||
| 4527 | return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value); | 4463 | return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value); |
| 4528 | } | 4464 | } |
| 4529 | case BuiltinFnIdSetGlobalSection: | ||
| 4530 | case BuiltinFnIdSetGlobalLinkage: | ||
| 4531 | { | ||
| 4532 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4533 | if (arg0_node->type != NodeTypeSymbol) { | ||
| 4534 | add_node_error(irb->codegen, arg0_node, buf_sprintf("expected identifier")); | ||
| 4535 | return irb->codegen->invalid_instruction; | ||
| 4536 | } | ||
| 4537 | Buf *variable_name = arg0_node->data.symbol_expr.symbol; | ||
| 4538 | Tld *tld = find_decl(irb->codegen, scope, variable_name); | ||
| 4539 | if (!tld) { | ||
| 4540 | add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", | ||
| 4541 | buf_ptr(variable_name))); | ||
| 4542 | return irb->codegen->invalid_instruction; | ||
| 4543 | } | ||
| 4544 | if (tld->id != TldIdVar && tld->id != TldIdFn) { | ||
| 4545 | add_node_error(irb->codegen, node, buf_sprintf("'%s' must be global variable or function", | ||
| 4546 | buf_ptr(variable_name))); | ||
| 4547 | return irb->codegen->invalid_instruction; | ||
| 4548 | } | ||
| 4549 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 4550 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 4551 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 4552 | return arg1_value; | ||
| 4553 | |||
| 4554 | if (builtin_fn->id == BuiltinFnIdSetGlobalSection) { | ||
| 4555 | return ir_build_set_global_section(irb, scope, node, tld, arg1_value); | ||
| 4556 | } else if (builtin_fn->id == BuiltinFnIdSetGlobalLinkage) { | ||
| 4557 | return ir_build_set_global_linkage(irb, scope, node, tld, arg1_value); | ||
| 4558 | } else { | ||
| 4559 | zig_unreachable(); | ||
| 4560 | } | ||
| 4561 | } | ||
| 4562 | case BuiltinFnIdPanic: | 4465 | case BuiltinFnIdPanic: |
| 4563 | { | 4466 | { |
| 4564 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 4467 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | @@ -4672,6 +4575,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4672,6 +4575,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4672 | return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value); | 4575 | return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value); |
| 4673 | } | 4576 | } |
| 4674 | case BuiltinFnIdInlineCall: | 4577 | case BuiltinFnIdInlineCall: |
| 4578 | case BuiltinFnIdNoInlineCall: | ||
| 4675 | { | 4579 | { |
| 4676 | if (node->data.fn_call_expr.params.length == 0) { | 4580 | if (node->data.fn_call_expr.params.length == 0) { |
| 4677 | add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0")); | 4581 | add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0")); |
| ... | @@ -4692,8 +4596,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4692,8 +4596,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4692 | if (args[i] == irb->codegen->invalid_instruction) | 4596 | if (args[i] == irb->codegen->invalid_instruction) |
| 4693 | return args[i]; | 4597 | return args[i]; |
| 4694 | } | 4598 | } |
| 4599 | FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever; | ||
| 4695 | 4600 | ||
| 4696 | return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, true); | 4601 | return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline); |
| 4697 | } | 4602 | } |
| 4698 | case BuiltinFnIdTypeId: | 4603 | case BuiltinFnIdTypeId: |
| 4699 | { | 4604 | { |
| ... | @@ -4780,6 +4685,25 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4780,6 +4685,25 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4780 | 4685 | ||
| 4781 | return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value); | 4686 | return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value); |
| 4782 | } | 4687 | } |
| 4688 | case BuiltinFnIdExport: | ||
| 4689 | { | ||
| 4690 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4691 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 4692 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 4693 | return arg0_value; | ||
| 4694 | |||
| 4695 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 4696 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 4697 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 4698 | return arg1_value; | ||
| 4699 | |||
| 4700 | AstNode *arg2_node = node->data.fn_call_expr.params.at(2); | ||
| 4701 | IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); | ||
| 4702 | if (arg2_value == irb->codegen->invalid_instruction) | ||
| 4703 | return arg2_value; | ||
| 4704 | |||
| 4705 | return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value); | ||
| 4706 | } | ||
| 4783 | } | 4707 | } |
| 4784 | zig_unreachable(); | 4708 | zig_unreachable(); |
| 4785 | } | 4709 | } |
| ... | @@ -4804,7 +4728,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node | ... | @@ -4804,7 +4728,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 4804 | return args[i]; | 4728 | return args[i]; |
| 4805 | } | 4729 | } |
| 4806 | 4730 | ||
| 4807 | return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, false); | 4731 | return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto); |
| 4808 | } | 4732 | } |
| 4809 | 4733 | ||
| 4810 | static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | 4734 | static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { |
| ... | @@ -4895,13 +4819,18 @@ static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -4895,13 +4819,18 @@ static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *n |
| 4895 | AstNode *expr_node = node->data.addr_of_expr.op_expr; | 4819 | AstNode *expr_node = node->data.addr_of_expr.op_expr; |
| 4896 | AstNode *align_expr = node->data.addr_of_expr.align_expr; | 4820 | AstNode *align_expr = node->data.addr_of_expr.align_expr; |
| 4897 | 4821 | ||
| 4898 | if (align_expr == nullptr) { | 4822 | if (align_expr == nullptr && !is_const && !is_volatile) { |
| 4899 | return ir_gen_node_extra(irb, expr_node, scope, make_lval_addr(is_const, is_volatile)); | 4823 | return ir_gen_node_extra(irb, expr_node, scope, make_lval_addr(is_const, is_volatile)); |
| 4900 | } | 4824 | } |
| 4901 | 4825 | ||
| 4902 | IrInstruction *align_value = ir_gen_node(irb, align_expr, scope); | 4826 | IrInstruction *align_value; |
| 4903 | if (align_value == irb->codegen->invalid_instruction) | 4827 | if (align_expr != nullptr) { |
| 4904 | return align_value; | 4828 | align_value = ir_gen_node(irb, align_expr, scope); |
| 4829 | if (align_value == irb->codegen->invalid_instruction) | ||
| 4830 | return align_value; | ||
| 4831 | } else { | ||
| 4832 | align_value = nullptr; | ||
| 4833 | } | ||
| 4905 | 4834 | ||
| 4906 | IrInstruction *child_type = ir_gen_node(irb, expr_node, scope); | 4835 | IrInstruction *child_type = ir_gen_node(irb, expr_node, scope); |
| 4907 | if (child_type == irb->codegen->invalid_instruction) | 4836 | if (child_type == irb->codegen->invalid_instruction) |
| ... | @@ -5078,7 +5007,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -5078,7 +5007,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod |
| 5078 | bool is_const = variable_declaration->is_const; | 5007 | bool is_const = variable_declaration->is_const; |
| 5079 | bool is_extern = variable_declaration->is_extern; | 5008 | bool is_extern = variable_declaration->is_extern; |
| 5080 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, | 5009 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, |
| 5081 | ir_should_inline(irb->exec, scope) || variable_declaration->is_inline); | 5010 | ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime); |
| 5082 | VariableTableEntry *var = ir_create_var(irb, node, scope, variable_declaration->symbol, | 5011 | VariableTableEntry *var = ir_create_var(irb, node, scope, variable_declaration->symbol, |
| 5083 | is_const, is_const, is_shadowable, is_comptime); | 5012 | is_const, is_const, is_shadowable, is_comptime); |
| 5084 | // we detect IrInstructionIdDeclVar in gen_block to make sure the next node | 5013 | // we detect IrInstructionIdDeclVar in gen_block to make sure the next node |
| ... | @@ -5097,13 +5026,16 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -5097,13 +5026,16 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod |
| 5097 | return align_value; | 5026 | return align_value; |
| 5098 | } | 5027 | } |
| 5099 | 5028 | ||
| 5029 | if (variable_declaration->section_expr != nullptr) { | ||
| 5030 | add_node_error(irb->codegen, variable_declaration->section_expr, | ||
| 5031 | buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); | ||
| 5032 | } | ||
| 5033 | |||
| 5100 | IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope); | 5034 | IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope); |
| 5101 | if (init_value == irb->codegen->invalid_instruction) | 5035 | if (init_value == irb->codegen->invalid_instruction) |
| 5102 | return init_value; | 5036 | return init_value; |
| 5103 | 5037 | ||
| 5104 | IrInstruction *result = ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value); | 5038 | return ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value); |
| 5105 | var->decl_instruction = result; | ||
| 5106 | return result; | ||
| 5107 | } | 5039 | } |
| 5108 | 5040 | ||
| 5109 | static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | 5041 | static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { |
| ... | @@ -6015,22 +5947,6 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6015,22 +5947,6 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6015 | return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); | 5947 | return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); |
| 6016 | } | 5948 | } |
| 6017 | 5949 | ||
| 6018 | static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) { | ||
| 6019 | assert(node->type == NodeTypeGoto); | ||
| 6020 | |||
| 6021 | // make a placeholder unreachable statement and a note to come back and | ||
| 6022 | // replace the instruction with a branch instruction | ||
| 6023 | IrGotoItem *goto_item = irb->exec->goto_list.add_one(); | ||
| 6024 | goto_item->bb = irb->current_basic_block; | ||
| 6025 | goto_item->instruction_index = irb->current_basic_block->instruction_list.length; | ||
| 6026 | goto_item->source_node = node; | ||
| 6027 | goto_item->scope = scope; | ||
| 6028 | |||
| 6029 | // we don't know if we need to generate defer expressions yet | ||
| 6030 | // we do that later when we find out which label we're jumping to. | ||
| 6031 | return ir_build_unreachable(irb, scope, node); | ||
| 6032 | } | ||
| 6033 | |||
| 6034 | static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) { | 5950 | static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) { |
| 6035 | assert(node->type == NodeTypeCompTime); | 5951 | assert(node->type == NodeTypeCompTime); |
| 6036 | 5952 | ||
| ... | @@ -6038,6 +5954,31 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -6038,6 +5954,31 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo |
| 6038 | return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval); | 5954 | return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval); |
| 6039 | } | 5955 | } |
| 6040 | 5956 | ||
| 5957 | static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) { | ||
| 5958 | IrInstruction *is_comptime; | ||
| 5959 | if (ir_should_inline(irb->exec, break_scope)) { | ||
| 5960 | is_comptime = ir_build_const_bool(irb, break_scope, node, true); | ||
| 5961 | } else { | ||
| 5962 | is_comptime = block_scope->is_comptime; | ||
| 5963 | } | ||
| 5964 | |||
| 5965 | IrInstruction *result_value; | ||
| 5966 | if (node->data.break_expr.expr) { | ||
| 5967 | result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope); | ||
| 5968 | if (result_value == irb->codegen->invalid_instruction) | ||
| 5969 | return irb->codegen->invalid_instruction; | ||
| 5970 | } else { | ||
| 5971 | result_value = ir_build_const_void(irb, break_scope, node); | ||
| 5972 | } | ||
| 5973 | |||
| 5974 | IrBasicBlock *dest_block = block_scope->end_block; | ||
| 5975 | ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false); | ||
| 5976 | |||
| 5977 | block_scope->incoming_blocks->append(irb->current_basic_block); | ||
| 5978 | block_scope->incoming_values->append(result_value); | ||
| 5979 | return ir_build_br(irb, break_scope, node, dest_block, is_comptime); | ||
| 5980 | } | ||
| 5981 | |||
| 6041 | static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) { | 5982 | static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) { |
| 6042 | assert(node->type == NodeTypeBreak); | 5983 | assert(node->type == NodeTypeBreak); |
| 6043 | 5984 | ||
| ... | @@ -6045,19 +5986,38 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode * | ... | @@ -6045,19 +5986,38 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode * |
| 6045 | // * function definition scope or global scope => error, break outside loop | 5986 | // * function definition scope or global scope => error, break outside loop |
| 6046 | // * defer expression scope => error, cannot break out of defer expression | 5987 | // * defer expression scope => error, cannot break out of defer expression |
| 6047 | // * loop scope => OK | 5988 | // * loop scope => OK |
| 5989 | // * (if it's a labeled break) labeled block => OK | ||
| 6048 | 5990 | ||
| 6049 | Scope *search_scope = break_scope; | 5991 | Scope *search_scope = break_scope; |
| 6050 | ScopeLoop *loop_scope; | 5992 | ScopeLoop *loop_scope; |
| 6051 | for (;;) { | 5993 | for (;;) { |
| 6052 | if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { | 5994 | if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { |
| 6053 | add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop")); | 5995 | if (node->data.break_expr.name != nullptr) { |
| 6054 | return irb->codegen->invalid_instruction; | 5996 | add_node_error(irb->codegen, node, buf_sprintf("label not found: '%s'", buf_ptr(node->data.break_expr.name))); |
| 5997 | return irb->codegen->invalid_instruction; | ||
| 5998 | } else { | ||
| 5999 | add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop")); | ||
| 6000 | return irb->codegen->invalid_instruction; | ||
| 6001 | } | ||
| 6055 | } else if (search_scope->id == ScopeIdDeferExpr) { | 6002 | } else if (search_scope->id == ScopeIdDeferExpr) { |
| 6056 | add_node_error(irb->codegen, node, buf_sprintf("cannot break out of defer expression")); | 6003 | add_node_error(irb->codegen, node, buf_sprintf("cannot break out of defer expression")); |
| 6057 | return irb->codegen->invalid_instruction; | 6004 | return irb->codegen->invalid_instruction; |
| 6058 | } else if (search_scope->id == ScopeIdLoop) { | 6005 | } else if (search_scope->id == ScopeIdLoop) { |
| 6059 | loop_scope = (ScopeLoop *)search_scope; | 6006 | ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; |
| 6060 | break; | 6007 | if (node->data.break_expr.name == nullptr || |
| 6008 | (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name))) | ||
| 6009 | { | ||
| 6010 | loop_scope = this_loop_scope; | ||
| 6011 | break; | ||
| 6012 | } | ||
| 6013 | } else if (search_scope->id == ScopeIdBlock) { | ||
| 6014 | ScopeBlock *this_block_scope = (ScopeBlock *)search_scope; | ||
| 6015 | if (node->data.break_expr.name != nullptr && | ||
| 6016 | (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name))) | ||
| 6017 | { | ||
| 6018 | assert(this_block_scope->end_block != nullptr); | ||
| 6019 | return ir_gen_return_from_block(irb, break_scope, node, this_block_scope); | ||
| 6020 | } | ||
| 6061 | } | 6021 | } |
| 6062 | search_scope = search_scope->parent; | 6022 | search_scope = search_scope->parent; |
| 6063 | } | 6023 | } |
| ... | @@ -6098,14 +6058,24 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast | ... | @@ -6098,14 +6058,24 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast |
| 6098 | ScopeLoop *loop_scope; | 6058 | ScopeLoop *loop_scope; |
| 6099 | for (;;) { | 6059 | for (;;) { |
| 6100 | if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { | 6060 | if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { |
| 6101 | add_node_error(irb->codegen, node, buf_sprintf("continue expression outside loop")); | 6061 | if (node->data.continue_expr.name != nullptr) { |
| 6102 | return irb->codegen->invalid_instruction; | 6062 | add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name))); |
| 6063 | return irb->codegen->invalid_instruction; | ||
| 6064 | } else { | ||
| 6065 | add_node_error(irb->codegen, node, buf_sprintf("continue expression outside loop")); | ||
| 6066 | return irb->codegen->invalid_instruction; | ||
| 6067 | } | ||
| 6103 | } else if (search_scope->id == ScopeIdDeferExpr) { | 6068 | } else if (search_scope->id == ScopeIdDeferExpr) { |
| 6104 | add_node_error(irb->codegen, node, buf_sprintf("cannot continue out of defer expression")); | 6069 | add_node_error(irb->codegen, node, buf_sprintf("cannot continue out of defer expression")); |
| 6105 | return irb->codegen->invalid_instruction; | 6070 | return irb->codegen->invalid_instruction; |
| 6106 | } else if (search_scope->id == ScopeIdLoop) { | 6071 | } else if (search_scope->id == ScopeIdLoop) { |
| 6107 | loop_scope = (ScopeLoop *)search_scope; | 6072 | ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; |
| 6108 | break; | 6073 | if (node->data.continue_expr.name == nullptr || |
| 6074 | (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name))) | ||
| 6075 | { | ||
| 6076 | loop_scope = this_loop_scope; | ||
| 6077 | break; | ||
| 6078 | } | ||
| 6109 | } | 6079 | } |
| 6110 | search_scope = search_scope->parent; | 6080 | search_scope = search_scope->parent; |
| 6111 | } | 6081 | } |
| ... | @@ -6347,7 +6317,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -6347,7 +6317,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 6347 | case NodeTypeSwitchProng: | 6317 | case NodeTypeSwitchProng: |
| 6348 | case NodeTypeSwitchRange: | 6318 | case NodeTypeSwitchRange: |
| 6349 | case NodeTypeStructField: | 6319 | case NodeTypeStructField: |
| 6350 | case NodeTypeLabel: | 6320 | case NodeTypeFnDef: |
| 6321 | case NodeTypeFnDecl: | ||
| 6322 | case NodeTypeErrorValueDecl: | ||
| 6323 | case NodeTypeTestDecl: | ||
| 6351 | zig_unreachable(); | 6324 | zig_unreachable(); |
| 6352 | case NodeTypeBlock: | 6325 | case NodeTypeBlock: |
| 6353 | return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); | 6326 | return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); |
| ... | @@ -6407,8 +6380,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -6407,8 +6380,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 6407 | return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval); | 6380 | return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval); |
| 6408 | case NodeTypeSwitchExpr: | 6381 | case NodeTypeSwitchExpr: |
| 6409 | return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); | 6382 | return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); |
| 6410 | case NodeTypeGoto: | ||
| 6411 | return ir_lval_wrap(irb, scope, ir_gen_goto(irb, scope, node), lval); | ||
| 6412 | case NodeTypeCompTime: | 6383 | case NodeTypeCompTime: |
| 6413 | return ir_gen_comptime(irb, scope, node, lval); | 6384 | return ir_gen_comptime(irb, scope, node, lval); |
| 6414 | case NodeTypeErrorType: | 6385 | case NodeTypeErrorType: |
| ... | @@ -6429,14 +6400,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -6429,14 +6400,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 6429 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); | 6400 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); |
| 6430 | case NodeTypeFnProto: | 6401 | case NodeTypeFnProto: |
| 6431 | return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); | 6402 | return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); |
| 6432 | case NodeTypeFnDef: | ||
| 6433 | zig_panic("TODO IR gen NodeTypeFnDef"); | ||
| 6434 | case NodeTypeFnDecl: | ||
| 6435 | zig_panic("TODO IR gen NodeTypeFnDecl"); | ||
| 6436 | case NodeTypeErrorValueDecl: | ||
| 6437 | zig_panic("TODO IR gen NodeTypeErrorValueDecl"); | ||
| 6438 | case NodeTypeTestDecl: | ||
| 6439 | zig_panic("TODO IR gen NodeTypeTestDecl"); | ||
| 6440 | } | 6403 | } |
| 6441 | zig_unreachable(); | 6404 | zig_unreachable(); |
| 6442 | } | 6405 | } |
| ... | @@ -6451,70 +6414,6 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { | ... | @@ -6451,70 +6414,6 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { |
| 6451 | return ir_gen_node_extra(irb, node, scope, LVAL_NONE); | 6414 | return ir_gen_node_extra(irb, node, scope, LVAL_NONE); |
| 6452 | } | 6415 | } |
| 6453 | 6416 | ||
| 6454 | static bool ir_goto_pass2(IrBuilder *irb) { | ||
| 6455 | for (size_t i = 0; i < irb->exec->goto_list.length; i += 1) { | ||
| 6456 | IrGotoItem *goto_item = &irb->exec->goto_list.at(i); | ||
| 6457 | AstNode *source_node = goto_item->source_node; | ||
| 6458 | |||
| 6459 | // Since a goto will always end a basic block, we move the "current instruction" | ||
| 6460 | // index back to over the placeholder unreachable instruction and begin overwriting | ||
| 6461 | irb->current_basic_block = goto_item->bb; | ||
| 6462 | irb->current_basic_block->instruction_list.resize(goto_item->instruction_index); | ||
| 6463 | |||
| 6464 | Buf *label_name = source_node->data.goto_expr.name; | ||
| 6465 | |||
| 6466 | // Search up the scope until we find one of these things: | ||
| 6467 | // * A block scope with the label in it => OK | ||
| 6468 | // * A defer expression scope => error, error, cannot leave defer expression | ||
| 6469 | // * Top level scope => error, didn't find label | ||
| 6470 | |||
| 6471 | LabelTableEntry *label; | ||
| 6472 | Scope *search_scope = goto_item->scope; | ||
| 6473 | for (;;) { | ||
| 6474 | if (search_scope == nullptr) { | ||
| 6475 | add_node_error(irb->codegen, source_node, | ||
| 6476 | buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); | ||
| 6477 | return false; | ||
| 6478 | } else if (search_scope->id == ScopeIdBlock) { | ||
| 6479 | ScopeBlock *block_scope = (ScopeBlock *)search_scope; | ||
| 6480 | auto entry = block_scope->label_table.maybe_get(label_name); | ||
| 6481 | if (entry) { | ||
| 6482 | label = entry->value; | ||
| 6483 | break; | ||
| 6484 | } | ||
| 6485 | } else if (search_scope->id == ScopeIdDeferExpr) { | ||
| 6486 | add_node_error(irb->codegen, source_node, | ||
| 6487 | buf_sprintf("cannot goto out of defer expression")); | ||
| 6488 | return false; | ||
| 6489 | } | ||
| 6490 | search_scope = search_scope->parent; | ||
| 6491 | } | ||
| 6492 | |||
| 6493 | label->used = true; | ||
| 6494 | |||
| 6495 | IrInstruction *is_comptime = ir_build_const_bool(irb, goto_item->scope, source_node, | ||
| 6496 | ir_should_inline(irb->exec, goto_item->scope) || source_node->data.goto_expr.is_inline); | ||
| 6497 | if (!ir_gen_defers_for_block(irb, goto_item->scope, label->bb->scope, false)) { | ||
| 6498 | add_node_error(irb->codegen, source_node, | ||
| 6499 | buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); | ||
| 6500 | return false; | ||
| 6501 | } | ||
| 6502 | ir_build_br(irb, goto_item->scope, source_node, label->bb, is_comptime); | ||
| 6503 | } | ||
| 6504 | |||
| 6505 | for (size_t i = 0; i < irb->exec->all_labels.length; i += 1) { | ||
| 6506 | LabelTableEntry *label = irb->exec->all_labels.at(i); | ||
| 6507 | if (!label->used) { | ||
| 6508 | add_node_error(irb->codegen, label->decl_node, | ||
| 6509 | buf_sprintf("label '%s' defined but not used", | ||
| 6510 | buf_ptr(label->decl_node->data.label.name))); | ||
| 6511 | return false; | ||
| 6512 | } | ||
| 6513 | } | ||
| 6514 | |||
| 6515 | return true; | ||
| 6516 | } | ||
| 6517 | |||
| 6518 | static void invalidate_exec(IrExecutable *exec) { | 6417 | static void invalidate_exec(IrExecutable *exec) { |
| 6519 | if (exec->invalid) | 6418 | if (exec->invalid) |
| 6520 | return; | 6419 | return; |
| ... | @@ -6551,11 +6450,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6551,11 +6450,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6551 | ir_mark_gen(ir_build_return(irb, scope, result->source_node, result)); | 6450 | ir_mark_gen(ir_build_return(irb, scope, result->source_node, result)); |
| 6552 | } | 6451 | } |
| 6553 | 6452 | ||
| 6554 | if (!ir_goto_pass2(irb)) { | ||
| 6555 | invalidate_exec(ir_executable); | ||
| 6556 | return false; | ||
| 6557 | } | ||
| 6558 | |||
| 6559 | return true; | 6453 | return true; |
| 6560 | } | 6454 | } |
| 6561 | 6455 | ||
| ... | @@ -7468,6 +7362,41 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -7468,6 +7362,41 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 7468 | } | 7362 | } |
| 7469 | } | 7363 | } |
| 7470 | 7364 | ||
| 7365 | // implicit union to its enum tag type | ||
| 7366 | if (expected_type->id == TypeTableEntryIdEnum && actual_type->id == TypeTableEntryIdUnion && | ||
| 7367 | (actual_type->data.unionation.decl_node->data.container_decl.auto_enum || | ||
| 7368 | actual_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | ||
| 7369 | { | ||
| 7370 | type_ensure_zero_bits_known(ira->codegen, actual_type); | ||
| 7371 | if (actual_type->data.unionation.tag_type == expected_type) { | ||
| 7372 | return ImplicitCastMatchResultYes; | ||
| 7373 | } | ||
| 7374 | } | ||
| 7375 | |||
| 7376 | // implicit enum to union which has the enum as the tag type | ||
| 7377 | if (expected_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum && | ||
| 7378 | (expected_type->data.unionation.decl_node->data.container_decl.auto_enum || | ||
| 7379 | expected_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | ||
| 7380 | { | ||
| 7381 | type_ensure_zero_bits_known(ira->codegen, expected_type); | ||
| 7382 | if (expected_type->data.unionation.tag_type == actual_type) { | ||
| 7383 | return ImplicitCastMatchResultYes; | ||
| 7384 | } | ||
| 7385 | } | ||
| 7386 | |||
| 7387 | // implicit enum to &const union which has the enum as the tag type | ||
| 7388 | if (actual_type->id == TypeTableEntryIdEnum && expected_type->id == TypeTableEntryIdPointer) { | ||
| 7389 | TypeTableEntry *union_type = expected_type->data.pointer.child_type; | ||
| 7390 | if (union_type->data.unionation.decl_node->data.container_decl.auto_enum || | ||
| 7391 | union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr) | ||
| 7392 | { | ||
| 7393 | type_ensure_zero_bits_known(ira->codegen, union_type); | ||
| 7394 | if (union_type->data.unionation.tag_type == actual_type) { | ||
| 7395 | return ImplicitCastMatchResultYes; | ||
| 7396 | } | ||
| 7397 | } | ||
| 7398 | } | ||
| 7399 | |||
| 7471 | // implicit undefined literal to anything | 7400 | // implicit undefined literal to anything |
| 7472 | if (actual_type->id == TypeTableEntryIdUndefLit) { | 7401 | if (actual_type->id == TypeTableEntryIdUndefLit) { |
| 7473 | return ImplicitCastMatchResultYes; | 7402 | return ImplicitCastMatchResultYes; |
| ... | @@ -7497,33 +7426,53 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -7497,33 +7426,53 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 7497 | IrInstruction *cur_inst = instructions[i]; | 7426 | IrInstruction *cur_inst = instructions[i]; |
| 7498 | TypeTableEntry *cur_type = cur_inst->value.type; | 7427 | TypeTableEntry *cur_type = cur_inst->value.type; |
| 7499 | TypeTableEntry *prev_type = prev_inst->value.type; | 7428 | TypeTableEntry *prev_type = prev_inst->value.type; |
| 7429 | |||
| 7500 | if (type_is_invalid(cur_type)) { | 7430 | if (type_is_invalid(cur_type)) { |
| 7501 | return cur_type; | 7431 | return cur_type; |
| 7502 | } else if (prev_type->id == TypeTableEntryIdUnreachable) { | 7432 | } |
| 7433 | |||
| 7434 | if (prev_type->id == TypeTableEntryIdUnreachable) { | ||
| 7503 | prev_inst = cur_inst; | 7435 | prev_inst = cur_inst; |
| 7504 | } else if (cur_type->id == TypeTableEntryIdUnreachable) { | ||
| 7505 | continue; | 7436 | continue; |
| 7506 | } else if (prev_type->id == TypeTableEntryIdPureError) { | 7437 | } |
| 7438 | |||
| 7439 | if (cur_type->id == TypeTableEntryIdUnreachable) { | ||
| 7440 | continue; | ||
| 7441 | } | ||
| 7442 | |||
| 7443 | if (prev_type->id == TypeTableEntryIdPureError) { | ||
| 7507 | prev_inst = cur_inst; | 7444 | prev_inst = cur_inst; |
| 7508 | continue; | 7445 | continue; |
| 7509 | } else if (prev_type->id == TypeTableEntryIdNullLit) { | 7446 | } |
| 7447 | |||
| 7448 | if (prev_type->id == TypeTableEntryIdNullLit) { | ||
| 7510 | prev_inst = cur_inst; | 7449 | prev_inst = cur_inst; |
| 7511 | continue; | 7450 | continue; |
| 7512 | } else if (cur_type->id == TypeTableEntryIdPureError) { | 7451 | } |
| 7452 | |||
| 7453 | if (cur_type->id == TypeTableEntryIdPureError) { | ||
| 7513 | if (prev_type->id == TypeTableEntryIdArray) { | 7454 | if (prev_type->id == TypeTableEntryIdArray) { |
| 7514 | convert_to_const_slice = true; | 7455 | convert_to_const_slice = true; |
| 7515 | } | 7456 | } |
| 7516 | any_are_pure_error = true; | 7457 | any_are_pure_error = true; |
| 7517 | continue; | 7458 | continue; |
| 7518 | } else if (cur_type->id == TypeTableEntryIdNullLit) { | 7459 | } |
| 7460 | |||
| 7461 | if (cur_type->id == TypeTableEntryIdNullLit) { | ||
| 7519 | any_are_null = true; | 7462 | any_are_null = true; |
| 7520 | continue; | 7463 | continue; |
| 7521 | } else if (types_match_const_cast_only(prev_type, cur_type)) { | 7464 | } |
| 7465 | |||
| 7466 | if (types_match_const_cast_only(prev_type, cur_type)) { | ||
| 7522 | continue; | 7467 | continue; |
| 7523 | } else if (types_match_const_cast_only(cur_type, prev_type)) { | 7468 | } |
| 7469 | |||
| 7470 | if (types_match_const_cast_only(cur_type, prev_type)) { | ||
| 7524 | prev_inst = cur_inst; | 7471 | prev_inst = cur_inst; |
| 7525 | continue; | 7472 | continue; |
| 7526 | } else if (prev_type->id == TypeTableEntryIdInt && | 7473 | } |
| 7474 | |||
| 7475 | if (prev_type->id == TypeTableEntryIdInt && | ||
| 7527 | cur_type->id == TypeTableEntryIdInt && | 7476 | cur_type->id == TypeTableEntryIdInt && |
| 7528 | prev_type->data.integral.is_signed == cur_type->data.integral.is_signed) | 7477 | prev_type->data.integral.is_signed == cur_type->data.integral.is_signed) |
| 7529 | { | 7478 | { |
| ... | @@ -7531,36 +7480,51 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -7531,36 +7480,51 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 7531 | prev_inst = cur_inst; | 7480 | prev_inst = cur_inst; |
| 7532 | } | 7481 | } |
| 7533 | continue; | 7482 | continue; |
| 7534 | } else if (prev_type->id == TypeTableEntryIdFloat && | 7483 | } |
| 7535 | cur_type->id == TypeTableEntryIdFloat) | 7484 | |
| 7536 | { | 7485 | if (prev_type->id == TypeTableEntryIdFloat && cur_type->id == TypeTableEntryIdFloat) { |
| 7537 | if (cur_type->data.floating.bit_count > prev_type->data.floating.bit_count) { | 7486 | if (cur_type->data.floating.bit_count > prev_type->data.floating.bit_count) { |
| 7538 | prev_inst = cur_inst; | 7487 | prev_inst = cur_inst; |
| 7539 | } | 7488 | } |
| 7540 | } else if (prev_type->id == TypeTableEntryIdErrorUnion && | 7489 | continue; |
| 7490 | } | ||
| 7491 | |||
| 7492 | if (prev_type->id == TypeTableEntryIdErrorUnion && | ||
| 7541 | types_match_const_cast_only(prev_type->data.error.child_type, cur_type)) | 7493 | types_match_const_cast_only(prev_type->data.error.child_type, cur_type)) |
| 7542 | { | 7494 | { |
| 7543 | continue; | 7495 | continue; |
| 7544 | } else if (cur_type->id == TypeTableEntryIdErrorUnion && | 7496 | } |
| 7497 | |||
| 7498 | if (cur_type->id == TypeTableEntryIdErrorUnion && | ||
| 7545 | types_match_const_cast_only(cur_type->data.error.child_type, prev_type)) | 7499 | types_match_const_cast_only(cur_type->data.error.child_type, prev_type)) |
| 7546 | { | 7500 | { |
| 7547 | prev_inst = cur_inst; | 7501 | prev_inst = cur_inst; |
| 7548 | continue; | 7502 | continue; |
| 7549 | } else if (prev_type->id == TypeTableEntryIdMaybe && | 7503 | } |
| 7504 | |||
| 7505 | if (prev_type->id == TypeTableEntryIdMaybe && | ||
| 7550 | types_match_const_cast_only(prev_type->data.maybe.child_type, cur_type)) | 7506 | types_match_const_cast_only(prev_type->data.maybe.child_type, cur_type)) |
| 7551 | { | 7507 | { |
| 7552 | continue; | 7508 | continue; |
| 7553 | } else if (cur_type->id == TypeTableEntryIdMaybe && | 7509 | } |
| 7510 | |||
| 7511 | if (cur_type->id == TypeTableEntryIdMaybe && | ||
| 7554 | types_match_const_cast_only(cur_type->data.maybe.child_type, prev_type)) | 7512 | types_match_const_cast_only(cur_type->data.maybe.child_type, prev_type)) |
| 7555 | { | 7513 | { |
| 7556 | prev_inst = cur_inst; | 7514 | prev_inst = cur_inst; |
| 7557 | continue; | 7515 | continue; |
| 7558 | } else if (cur_type->id == TypeTableEntryIdUndefLit) { | 7516 | } |
| 7517 | |||
| 7518 | if (cur_type->id == TypeTableEntryIdUndefLit) { | ||
| 7559 | continue; | 7519 | continue; |
| 7560 | } else if (prev_type->id == TypeTableEntryIdUndefLit) { | 7520 | } |
| 7521 | |||
| 7522 | if (prev_type->id == TypeTableEntryIdUndefLit) { | ||
| 7561 | prev_inst = cur_inst; | 7523 | prev_inst = cur_inst; |
| 7562 | continue; | 7524 | continue; |
| 7563 | } else if (prev_type->id == TypeTableEntryIdNumLitInt || | 7525 | } |
| 7526 | |||
| 7527 | if (prev_type->id == TypeTableEntryIdNumLitInt || | ||
| 7564 | prev_type->id == TypeTableEntryIdNumLitFloat) | 7528 | prev_type->id == TypeTableEntryIdNumLitFloat) |
| 7565 | { | 7529 | { |
| 7566 | if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type, false)) { | 7530 | if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type, false)) { |
| ... | @@ -7569,7 +7533,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -7569,7 +7533,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 7569 | } else { | 7533 | } else { |
| 7570 | return ira->codegen->builtin_types.entry_invalid; | 7534 | return ira->codegen->builtin_types.entry_invalid; |
| 7571 | } | 7535 | } |
| 7572 | } else if (cur_type->id == TypeTableEntryIdNumLitInt || | 7536 | } |
| 7537 | |||
| 7538 | if (cur_type->id == TypeTableEntryIdNumLitInt || | ||
| 7573 | cur_type->id == TypeTableEntryIdNumLitFloat) | 7539 | cur_type->id == TypeTableEntryIdNumLitFloat) |
| 7574 | { | 7540 | { |
| 7575 | if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type, false)) { | 7541 | if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type, false)) { |
| ... | @@ -7577,20 +7543,26 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -7577,20 +7543,26 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 7577 | } else { | 7543 | } else { |
| 7578 | return ira->codegen->builtin_types.entry_invalid; | 7544 | return ira->codegen->builtin_types.entry_invalid; |
| 7579 | } | 7545 | } |
| 7580 | } else if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && | 7546 | } |
| 7547 | |||
| 7548 | if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && | ||
| 7581 | cur_type->data.array.len != prev_type->data.array.len && | 7549 | cur_type->data.array.len != prev_type->data.array.len && |
| 7582 | types_match_const_cast_only(cur_type->data.array.child_type, prev_type->data.array.child_type)) | 7550 | types_match_const_cast_only(cur_type->data.array.child_type, prev_type->data.array.child_type)) |
| 7583 | { | 7551 | { |
| 7584 | convert_to_const_slice = true; | 7552 | convert_to_const_slice = true; |
| 7585 | prev_inst = cur_inst; | 7553 | prev_inst = cur_inst; |
| 7586 | continue; | 7554 | continue; |
| 7587 | } else if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && | 7555 | } |
| 7556 | |||
| 7557 | if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && | ||
| 7588 | cur_type->data.array.len != prev_type->data.array.len && | 7558 | cur_type->data.array.len != prev_type->data.array.len && |
| 7589 | types_match_const_cast_only(prev_type->data.array.child_type, cur_type->data.array.child_type)) | 7559 | types_match_const_cast_only(prev_type->data.array.child_type, cur_type->data.array.child_type)) |
| 7590 | { | 7560 | { |
| 7591 | convert_to_const_slice = true; | 7561 | convert_to_const_slice = true; |
| 7592 | continue; | 7562 | continue; |
| 7593 | } else if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) && | 7563 | } |
| 7564 | |||
| 7565 | if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) && | ||
| 7594 | (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || | 7566 | (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || |
| 7595 | cur_type->data.array.len == 0) && | 7567 | cur_type->data.array.len == 0) && |
| 7596 | types_match_const_cast_only(prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, | 7568 | types_match_const_cast_only(prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, |
| ... | @@ -7598,7 +7570,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -7598,7 +7570,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 7598 | { | 7570 | { |
| 7599 | convert_to_const_slice = false; | 7571 | convert_to_const_slice = false; |
| 7600 | continue; | 7572 | continue; |
| 7601 | } else if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) && | 7573 | } |
| 7574 | |||
| 7575 | if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) && | ||
| 7602 | (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || | 7576 | (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || |
| 7603 | prev_type->data.array.len == 0) && | 7577 | prev_type->data.array.len == 0) && |
| 7604 | types_match_const_cast_only(cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, | 7578 | types_match_const_cast_only(cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, |
| ... | @@ -7607,17 +7581,40 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -7607,17 +7581,40 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 7607 | prev_inst = cur_inst; | 7581 | prev_inst = cur_inst; |
| 7608 | convert_to_const_slice = false; | 7582 | convert_to_const_slice = false; |
| 7609 | continue; | 7583 | continue; |
| 7610 | } else { | 7584 | } |
| 7611 | ErrorMsg *msg = ir_add_error_node(ira, source_node, | ||
| 7612 | buf_sprintf("incompatible types: '%s' and '%s'", | ||
| 7613 | buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); | ||
| 7614 | add_error_note(ira->codegen, msg, prev_inst->source_node, | ||
| 7615 | buf_sprintf("type '%s' here", buf_ptr(&prev_type->name))); | ||
| 7616 | add_error_note(ira->codegen, msg, cur_inst->source_node, | ||
| 7617 | buf_sprintf("type '%s' here", buf_ptr(&cur_type->name))); | ||
| 7618 | 7585 | ||
| 7619 | return ira->codegen->builtin_types.entry_invalid; | 7586 | if (prev_type->id == TypeTableEntryIdEnum && cur_type->id == TypeTableEntryIdUnion && |
| 7587 | (cur_type->data.unionation.decl_node->data.container_decl.auto_enum || cur_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | ||
| 7588 | { | ||
| 7589 | type_ensure_zero_bits_known(ira->codegen, cur_type); | ||
| 7590 | if (type_is_invalid(cur_type)) | ||
| 7591 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7592 | if (cur_type->data.unionation.tag_type == prev_type) { | ||
| 7593 | continue; | ||
| 7594 | } | ||
| 7595 | } | ||
| 7596 | |||
| 7597 | if (cur_type->id == TypeTableEntryIdEnum && prev_type->id == TypeTableEntryIdUnion && | ||
| 7598 | (prev_type->data.unionation.decl_node->data.container_decl.auto_enum || prev_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | ||
| 7599 | { | ||
| 7600 | type_ensure_zero_bits_known(ira->codegen, prev_type); | ||
| 7601 | if (type_is_invalid(prev_type)) | ||
| 7602 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7603 | if (prev_type->data.unionation.tag_type == cur_type) { | ||
| 7604 | prev_inst = cur_inst; | ||
| 7605 | continue; | ||
| 7606 | } | ||
| 7620 | } | 7607 | } |
| 7608 | |||
| 7609 | ErrorMsg *msg = ir_add_error_node(ira, source_node, | ||
| 7610 | buf_sprintf("incompatible types: '%s' and '%s'", | ||
| 7611 | buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); | ||
| 7612 | add_error_note(ira->codegen, msg, prev_inst->source_node, | ||
| 7613 | buf_sprintf("type '%s' here", buf_ptr(&prev_type->name))); | ||
| 7614 | add_error_note(ira->codegen, msg, cur_inst->source_node, | ||
| 7615 | buf_sprintf("type '%s' here", buf_ptr(&cur_type->name))); | ||
| 7616 | |||
| 7617 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7621 | } | 7618 | } |
| 7622 | if (convert_to_const_slice) { | 7619 | if (convert_to_const_slice) { |
| 7623 | assert(prev_inst->value.type->id == TypeTableEntryIdArray); | 7620 | assert(prev_inst->value.type->id == TypeTableEntryIdArray); |
| ... | @@ -7664,8 +7661,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -7664,8 +7661,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 7664 | static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *type_entry) { | 7661 | static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *type_entry) { |
| 7665 | if (type_has_bits(type_entry) && handle_is_ptr(type_entry)) { | 7662 | if (type_has_bits(type_entry) && handle_is_ptr(type_entry)) { |
| 7666 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | 7663 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 7667 | assert(fn_entry); | 7664 | if (fn_entry != nullptr) { |
| 7668 | fn_entry->alloca_list.append(instruction); | 7665 | fn_entry->alloca_list.append(instruction); |
| 7666 | } | ||
| 7669 | } | 7667 | } |
| 7670 | } | 7668 | } |
| 7671 | 7669 | ||
| ... | @@ -7767,9 +7765,7 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7767,9 +7765,7 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7767 | IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op); | 7765 | IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op); |
| 7768 | result->value.type = wanted_type; | 7766 | result->value.type = wanted_type; |
| 7769 | if (need_alloca) { | 7767 | if (need_alloca) { |
| 7770 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | 7768 | ir_add_alloca(ira, result, wanted_type); |
| 7771 | if (fn_entry) | ||
| 7772 | fn_entry->alloca_list.append(result); | ||
| 7773 | } | 7769 | } |
| 7774 | return result; | 7770 | return result; |
| 7775 | } | 7771 | } |
| ... | @@ -8203,6 +8199,7 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -8203,6 +8199,7 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_ |
| 8203 | assert(fn_entry); | 8199 | assert(fn_entry); |
| 8204 | fn_entry->alloca_list.append(new_instruction); | 8200 | fn_entry->alloca_list.append(new_instruction); |
| 8205 | } | 8201 | } |
| 8202 | ir_add_alloca(ira, new_instruction, child_type); | ||
| 8206 | return new_instruction; | 8203 | return new_instruction; |
| 8207 | } | 8204 | } |
| 8208 | } | 8205 | } |
| ... | @@ -8246,13 +8243,15 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi | ... | @@ -8246,13 +8243,15 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi |
| 8246 | 8243 | ||
| 8247 | TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, | 8244 | TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, |
| 8248 | is_const, is_volatile, get_abi_alignment(ira->codegen, value->value.type), 0, 0); | 8245 | is_const, is_volatile, get_abi_alignment(ira->codegen, value->value.type), 0, 0); |
| 8249 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | ||
| 8250 | assert(fn_entry); | ||
| 8251 | IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope, | 8246 | IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope, |
| 8252 | source_instruction->source_node, value, is_const, is_volatile); | 8247 | source_instruction->source_node, value, is_const, is_volatile); |
| 8253 | new_instruction->value.type = ptr_type; | 8248 | new_instruction->value.type = ptr_type; |
| 8254 | new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; | 8249 | new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; |
| 8255 | fn_entry->alloca_list.append(new_instruction); | 8250 | if (type_has_bits(ptr_type)) { |
| 8251 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | ||
| 8252 | assert(fn_entry); | ||
| 8253 | fn_entry->alloca_list.append(new_instruction); | ||
| 8254 | } | ||
| 8256 | return new_instruction; | 8255 | return new_instruction; |
| 8257 | } | 8256 | } |
| 8258 | 8257 | ||
| ... | @@ -8370,6 +8369,63 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc | ... | @@ -8370,6 +8369,63 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc |
| 8370 | return result; | 8369 | return result; |
| 8371 | } | 8370 | } |
| 8372 | 8371 | ||
| 8372 | static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *source_instr, | ||
| 8373 | IrInstruction *target, TypeTableEntry *wanted_type) | ||
| 8374 | { | ||
| 8375 | assert(wanted_type->id == TypeTableEntryIdUnion); | ||
| 8376 | assert(target->value.type->id == TypeTableEntryIdEnum); | ||
| 8377 | |||
| 8378 | if (instr_is_comptime(target)) { | ||
| 8379 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | ||
| 8380 | if (!val) | ||
| 8381 | return ira->codegen->invalid_instruction; | ||
| 8382 | TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); | ||
| 8383 | assert(union_field != nullptr); | ||
| 8384 | type_ensure_zero_bits_known(ira->codegen, union_field->type_entry); | ||
| 8385 | if (!union_field->type_entry->zero_bits) { | ||
| 8386 | AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at( | ||
| 8387 | union_field->enum_field->decl_index); | ||
| 8388 | ErrorMsg *msg = ir_add_error(ira, source_instr, | ||
| 8389 | buf_sprintf("cast to union '%s' must initialize '%s' field '%s'", | ||
| 8390 | buf_ptr(&wanted_type->name), | ||
| 8391 | buf_ptr(&union_field->type_entry->name), | ||
| 8392 | buf_ptr(union_field->name))); | ||
| 8393 | add_error_note(ira->codegen, msg, field_node, | ||
| 8394 | buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); | ||
| 8395 | return ira->codegen->invalid_instruction; | ||
| 8396 | } | ||
| 8397 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | ||
| 8398 | source_instr->source_node, wanted_type); | ||
| 8399 | result->value.special = ConstValSpecialStatic; | ||
| 8400 | result->value.type = wanted_type; | ||
| 8401 | bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); | ||
| 8402 | return result; | ||
| 8403 | } | ||
| 8404 | |||
| 8405 | // if the union has all fields 0 bits, we can do it | ||
| 8406 | // and in fact it's a noop cast because the union value is just the enum value | ||
| 8407 | if (wanted_type->data.unionation.gen_field_count == 0) { | ||
| 8408 | IrInstruction *result = ir_build_cast(&ira->new_irb, target->scope, target->source_node, wanted_type, target, CastOpNoop); | ||
| 8409 | result->value.type = wanted_type; | ||
| 8410 | return result; | ||
| 8411 | } | ||
| 8412 | |||
| 8413 | ErrorMsg *msg = ir_add_error(ira, source_instr, | ||
| 8414 | buf_sprintf("runtime cast to union '%s' which has non-void fields", | ||
| 8415 | buf_ptr(&wanted_type->name))); | ||
| 8416 | for (uint32_t i = 0; i < wanted_type->data.unionation.src_field_count; i += 1) { | ||
| 8417 | TypeUnionField *union_field = &wanted_type->data.unionation.fields[i]; | ||
| 8418 | if (type_has_bits(union_field->type_entry)) { | ||
| 8419 | AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(i); | ||
| 8420 | add_error_note(ira->codegen, msg, field_node, | ||
| 8421 | buf_sprintf("field '%s' has type '%s'", | ||
| 8422 | buf_ptr(union_field->name), | ||
| 8423 | buf_ptr(&union_field->type_entry->name))); | ||
| 8424 | } | ||
| 8425 | } | ||
| 8426 | return ira->codegen->invalid_instruction; | ||
| 8427 | } | ||
| 8428 | |||
| 8373 | static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr, | 8429 | static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr, |
| 8374 | IrInstruction *target, TypeTableEntry *wanted_type) | 8430 | IrInstruction *target, TypeTableEntry *wanted_type) |
| 8375 | { | 8431 | { |
| ... | @@ -8436,14 +8492,16 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour | ... | @@ -8436,14 +8492,16 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour |
| 8436 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | 8492 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 8437 | if (!val) | 8493 | if (!val) |
| 8438 | return ira->codegen->invalid_instruction; | 8494 | return ira->codegen->invalid_instruction; |
| 8439 | BigInt enum_member_count; | 8495 | |
| 8440 | bigint_init_unsigned(&enum_member_count, wanted_type->data.enumeration.src_field_count); | 8496 | TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint); |
| 8441 | if (bigint_cmp(&val->data.x_bigint, &enum_member_count) != CmpLT) { | 8497 | if (field == nullptr) { |
| 8442 | Buf *val_buf = buf_alloc(); | 8498 | Buf *val_buf = buf_alloc(); |
| 8443 | bigint_append_buf(val_buf, &val->data.x_bigint, 10); | 8499 | bigint_append_buf(val_buf, &val->data.x_bigint, 10); |
| 8444 | ir_add_error(ira, source_instr, | 8500 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 8445 | buf_sprintf("integer value %s too big for enum '%s' which has %" PRIu32 " fields", | 8501 | buf_sprintf("enum '%s' has no tag matching integer value %s", |
| 8446 | buf_ptr(val_buf), buf_ptr(&wanted_type->name), wanted_type->data.enumeration.src_field_count)); | 8502 | buf_ptr(&wanted_type->name), buf_ptr(val_buf))); |
| 8503 | add_error_note(ira->codegen, msg, wanted_type->data.enumeration.decl_node, | ||
| 8504 | buf_sprintf("'%s' declared here", buf_ptr(&wanted_type->name))); | ||
| 8447 | return ira->codegen->invalid_instruction; | 8505 | return ira->codegen->invalid_instruction; |
| 8448 | } | 8506 | } |
| 8449 | 8507 | ||
| ... | @@ -8827,7 +8885,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -8827,7 +8885,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 8827 | if (actual_type->id == TypeTableEntryIdNumLitFloat || | 8885 | if (actual_type->id == TypeTableEntryIdNumLitFloat || |
| 8828 | actual_type->id == TypeTableEntryIdNumLitInt) | 8886 | actual_type->id == TypeTableEntryIdNumLitInt) |
| 8829 | { | 8887 | { |
| 8830 | if (wanted_type->id == TypeTableEntryIdPointer && | 8888 | if (wanted_type->id == TypeTableEntryIdEnum) { |
| 8889 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value); | ||
| 8890 | if (type_is_invalid(cast1->value.type)) | ||
| 8891 | return ira->codegen->invalid_instruction; | ||
| 8892 | |||
| 8893 | IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 8894 | if (type_is_invalid(cast2->value.type)) | ||
| 8895 | return ira->codegen->invalid_instruction; | ||
| 8896 | |||
| 8897 | return cast2; | ||
| 8898 | } else if (wanted_type->id == TypeTableEntryIdPointer && | ||
| 8831 | wanted_type->data.pointer.is_const) | 8899 | wanted_type->data.pointer.is_const) |
| 8832 | { | 8900 | { |
| 8833 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value); | 8901 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value); |
| ... | @@ -8907,6 +8975,38 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -8907,6 +8975,38 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 8907 | } | 8975 | } |
| 8908 | } | 8976 | } |
| 8909 | 8977 | ||
| 8978 | // explicit enum to union which has the enum as the tag type | ||
| 8979 | if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum && | ||
| 8980 | (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum || | ||
| 8981 | wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | ||
| 8982 | { | ||
| 8983 | type_ensure_zero_bits_known(ira->codegen, wanted_type); | ||
| 8984 | if (wanted_type->data.unionation.tag_type == actual_type) { | ||
| 8985 | return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type); | ||
| 8986 | } | ||
| 8987 | } | ||
| 8988 | |||
| 8989 | // explicit enum to &const union which has the enum as the tag type | ||
| 8990 | if (actual_type->id == TypeTableEntryIdEnum && wanted_type->id == TypeTableEntryIdPointer) { | ||
| 8991 | TypeTableEntry *union_type = wanted_type->data.pointer.child_type; | ||
| 8992 | if (union_type->data.unionation.decl_node->data.container_decl.auto_enum || | ||
| 8993 | union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr) | ||
| 8994 | { | ||
| 8995 | type_ensure_zero_bits_known(ira->codegen, union_type); | ||
| 8996 | if (union_type->data.unionation.tag_type == actual_type) { | ||
| 8997 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, union_type, value); | ||
| 8998 | if (type_is_invalid(cast1->value.type)) | ||
| 8999 | return ira->codegen->invalid_instruction; | ||
| 9000 | |||
| 9001 | IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 9002 | if (type_is_invalid(cast2->value.type)) | ||
| 9003 | return ira->codegen->invalid_instruction; | ||
| 9004 | |||
| 9005 | return cast2; | ||
| 9006 | } | ||
| 9007 | } | ||
| 9008 | } | ||
| 9009 | |||
| 8910 | // explicit cast from undefined to anything | 9010 | // explicit cast from undefined to anything |
| 8911 | if (actual_type->id == TypeTableEntryIdUndefLit) { | 9011 | if (actual_type->id == TypeTableEntryIdUndefLit) { |
| 8912 | return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type); | 9012 | return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type); |
| ... | @@ -9334,6 +9434,10 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -9334,6 +9434,10 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 9334 | TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2); | 9434 | TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2); |
| 9335 | if (type_is_invalid(resolved_type)) | 9435 | if (type_is_invalid(resolved_type)) |
| 9336 | return resolved_type; | 9436 | return resolved_type; |
| 9437 | type_ensure_zero_bits_known(ira->codegen, resolved_type); | ||
| 9438 | if (type_is_invalid(resolved_type)) | ||
| 9439 | return resolved_type; | ||
| 9440 | |||
| 9337 | 9441 | ||
| 9338 | AstNode *source_node = bin_op_instruction->base.source_node; | 9442 | AstNode *source_node = bin_op_instruction->base.source_node; |
| 9339 | switch (resolved_type->id) { | 9443 | switch (resolved_type->id) { |
| ... | @@ -9398,7 +9502,8 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -9398,7 +9502,8 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 9398 | 9502 | ||
| 9399 | ConstExprValue *op1_val = &casted_op1->value; | 9503 | ConstExprValue *op1_val = &casted_op1->value; |
| 9400 | ConstExprValue *op2_val = &casted_op2->value; | 9504 | ConstExprValue *op2_val = &casted_op2->value; |
| 9401 | if ((value_is_comptime(op1_val) && value_is_comptime(op2_val)) || resolved_type->id == TypeTableEntryIdVoid) { | 9505 | bool one_possible_value = !type_requires_comptime(resolved_type) && !type_has_bits(resolved_type); |
| 9506 | if (one_possible_value || (value_is_comptime(op1_val) && value_is_comptime(op2_val))) { | ||
| 9402 | bool answer; | 9507 | bool answer; |
| 9403 | if (resolved_type->id == TypeTableEntryIdNumLitFloat || resolved_type->id == TypeTableEntryIdFloat) { | 9508 | if (resolved_type->id == TypeTableEntryIdNumLitFloat || resolved_type->id == TypeTableEntryIdFloat) { |
| 9404 | Cmp cmp_result = float_cmp(op1_val, op2_val); | 9509 | Cmp cmp_result = float_cmp(op1_val, op2_val); |
| ... | @@ -9407,7 +9512,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -9407,7 +9512,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 9407 | Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); | 9512 | Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); |
| 9408 | answer = resolve_cmp_op_id(op_id, cmp_result); | 9513 | answer = resolve_cmp_op_id(op_id, cmp_result); |
| 9409 | } else { | 9514 | } else { |
| 9410 | bool are_equal = resolved_type->id == TypeTableEntryIdVoid || const_values_equal(op1_val, op2_val); | 9515 | bool are_equal = one_possible_value || const_values_equal(op1_val, op2_val); |
| 9411 | if (op_id == IrBinOpCmpEq) { | 9516 | if (op_id == IrBinOpCmpEq) { |
| 9412 | answer = are_equal; | 9517 | answer = are_equal; |
| 9413 | } else if (op_id == IrBinOpCmpNotEq) { | 9518 | } else if (op_id == IrBinOpCmpNotEq) { |
| ... | @@ -10265,6 +10370,170 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc | ... | @@ -10265,6 +10370,170 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc |
| 10265 | return ira->codegen->builtin_types.entry_void; | 10370 | return ira->codegen->builtin_types.entry_void; |
| 10266 | } | 10371 | } |
| 10267 | 10372 | ||
| 10373 | static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) { | ||
| 10374 | IrInstruction *name = instruction->name->other; | ||
| 10375 | Buf *symbol_name = ir_resolve_str(ira, name); | ||
| 10376 | if (symbol_name == nullptr) { | ||
| 10377 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10378 | } | ||
| 10379 | |||
| 10380 | IrInstruction *target = instruction->target->other; | ||
| 10381 | if (type_is_invalid(target->value.type)) { | ||
| 10382 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10383 | } | ||
| 10384 | |||
| 10385 | GlobalLinkageId global_linkage_id = GlobalLinkageIdStrong; | ||
| 10386 | if (instruction->linkage != nullptr) { | ||
| 10387 | IrInstruction *linkage_value = instruction->linkage->other; | ||
| 10388 | if (!ir_resolve_global_linkage(ira, linkage_value, &global_linkage_id)) { | ||
| 10389 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10390 | } | ||
| 10391 | } | ||
| 10392 | |||
| 10393 | auto entry = ira->codegen->exported_symbol_names.put_unique(symbol_name, instruction->base.source_node); | ||
| 10394 | if (entry) { | ||
| 10395 | AstNode *other_export_node = entry->value; | ||
| 10396 | ErrorMsg *msg = ir_add_error(ira, &instruction->base, | ||
| 10397 | buf_sprintf("exported symbol collision: '%s'", buf_ptr(symbol_name))); | ||
| 10398 | add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here")); | ||
| 10399 | } | ||
| 10400 | |||
| 10401 | switch (target->value.type->id) { | ||
| 10402 | case TypeTableEntryIdInvalid: | ||
| 10403 | case TypeTableEntryIdVar: | ||
| 10404 | case TypeTableEntryIdUnreachable: | ||
| 10405 | zig_unreachable(); | ||
| 10406 | case TypeTableEntryIdFn: { | ||
| 10407 | FnTableEntry *fn_entry = target->value.data.x_fn.fn_entry; | ||
| 10408 | CallingConvention cc = fn_entry->type_entry->data.fn.fn_type_id.cc; | ||
| 10409 | switch (cc) { | ||
| 10410 | case CallingConventionUnspecified: { | ||
| 10411 | ErrorMsg *msg = ir_add_error(ira, target, | ||
| 10412 | buf_sprintf("exported function must specify calling convention")); | ||
| 10413 | add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); | ||
| 10414 | } break; | ||
| 10415 | case CallingConventionC: | ||
| 10416 | case CallingConventionNaked: | ||
| 10417 | case CallingConventionCold: | ||
| 10418 | case CallingConventionStdcall: | ||
| 10419 | add_fn_export(ira->codegen, fn_entry, symbol_name, global_linkage_id, cc == CallingConventionC); | ||
| 10420 | break; | ||
| 10421 | } | ||
| 10422 | } break; | ||
| 10423 | case TypeTableEntryIdStruct: | ||
| 10424 | if (is_slice(target->value.type)) { | ||
| 10425 | ir_add_error(ira, target, | ||
| 10426 | buf_sprintf("unable to export value of type '%s'", buf_ptr(&target->value.type->name))); | ||
| 10427 | } else if (target->value.type->data.structure.layout != ContainerLayoutExtern) { | ||
| 10428 | ErrorMsg *msg = ir_add_error(ira, target, | ||
| 10429 | buf_sprintf("exported struct value must be declared extern")); | ||
| 10430 | add_error_note(ira->codegen, msg, target->value.type->data.structure.decl_node, buf_sprintf("declared here")); | ||
| 10431 | } | ||
| 10432 | break; | ||
| 10433 | case TypeTableEntryIdUnion: | ||
| 10434 | if (target->value.type->data.unionation.layout != ContainerLayoutExtern) { | ||
| 10435 | ErrorMsg *msg = ir_add_error(ira, target, | ||
| 10436 | buf_sprintf("exported union value must be declared extern")); | ||
| 10437 | add_error_note(ira->codegen, msg, target->value.type->data.unionation.decl_node, buf_sprintf("declared here")); | ||
| 10438 | } | ||
| 10439 | break; | ||
| 10440 | case TypeTableEntryIdEnum: | ||
| 10441 | if (target->value.type->data.enumeration.layout != ContainerLayoutExtern) { | ||
| 10442 | ErrorMsg *msg = ir_add_error(ira, target, | ||
| 10443 | buf_sprintf("exported enum value must be declared extern")); | ||
| 10444 | add_error_note(ira->codegen, msg, target->value.type->data.enumeration.decl_node, buf_sprintf("declared here")); | ||
| 10445 | } | ||
| 10446 | break; | ||
| 10447 | case TypeTableEntryIdMetaType: { | ||
| 10448 | TypeTableEntry *type_value = target->value.data.x_type; | ||
| 10449 | switch (type_value->id) { | ||
| 10450 | case TypeTableEntryIdInvalid: | ||
| 10451 | case TypeTableEntryIdVar: | ||
| 10452 | zig_unreachable(); | ||
| 10453 | case TypeTableEntryIdStruct: | ||
| 10454 | if (is_slice(type_value)) { | ||
| 10455 | ir_add_error(ira, target, | ||
| 10456 | buf_sprintf("unable to export type '%s'", buf_ptr(&type_value->name))); | ||
| 10457 | } else if (type_value->data.structure.layout != ContainerLayoutExtern) { | ||
| 10458 | ErrorMsg *msg = ir_add_error(ira, target, | ||
| 10459 | buf_sprintf("exported struct must be declared extern")); | ||
| 10460 | add_error_note(ira->codegen, msg, type_value->data.structure.decl_node, buf_sprintf("declared here")); | ||
| 10461 | } | ||
| 10462 | break; | ||
| 10463 | case TypeTableEntryIdUnion: | ||
| 10464 | if (type_value->data.unionation.layout != ContainerLayoutExtern) { | ||
| 10465 | ErrorMsg *msg = ir_add_error(ira, target, | ||
| 10466 | buf_sprintf("exported union must be declared extern")); | ||
| 10467 | add_error_note(ira->codegen, msg, type_value->data.unionation.decl_node, buf_sprintf("declared here")); | ||
| 10468 | } | ||
| 10469 | break; | ||
| 10470 | case TypeTableEntryIdEnum: | ||
| 10471 | if (type_value->data.enumeration.layout != ContainerLayoutExtern) { | ||
| 10472 | ErrorMsg *msg = ir_add_error(ira, target, | ||
| 10473 | buf_sprintf("exported enum must be declared extern")); | ||
| 10474 | add_error_note(ira->codegen, msg, type_value->data.enumeration.decl_node, buf_sprintf("declared here")); | ||
| 10475 | } | ||
| 10476 | break; | ||
| 10477 | case TypeTableEntryIdFn: { | ||
| 10478 | if (type_value->data.fn.fn_type_id.cc == CallingConventionUnspecified) { | ||
| 10479 | ir_add_error(ira, target, | ||
| 10480 | buf_sprintf("exported function type must specify calling convention")); | ||
| 10481 | } | ||
| 10482 | } break; | ||
| 10483 | case TypeTableEntryIdInt: | ||
| 10484 | case TypeTableEntryIdFloat: | ||
| 10485 | case TypeTableEntryIdPointer: | ||
| 10486 | case TypeTableEntryIdArray: | ||
| 10487 | case TypeTableEntryIdBool: | ||
| 10488 | break; | ||
| 10489 | case TypeTableEntryIdMetaType: | ||
| 10490 | case TypeTableEntryIdVoid: | ||
| 10491 | case TypeTableEntryIdUnreachable: | ||
| 10492 | case TypeTableEntryIdNumLitFloat: | ||
| 10493 | case TypeTableEntryIdNumLitInt: | ||
| 10494 | case TypeTableEntryIdUndefLit: | ||
| 10495 | case TypeTableEntryIdNullLit: | ||
| 10496 | case TypeTableEntryIdMaybe: | ||
| 10497 | case TypeTableEntryIdErrorUnion: | ||
| 10498 | case TypeTableEntryIdPureError: | ||
| 10499 | case TypeTableEntryIdNamespace: | ||
| 10500 | case TypeTableEntryIdBlock: | ||
| 10501 | case TypeTableEntryIdBoundFn: | ||
| 10502 | case TypeTableEntryIdArgTuple: | ||
| 10503 | case TypeTableEntryIdOpaque: | ||
| 10504 | ir_add_error(ira, target, | ||
| 10505 | buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name))); | ||
| 10506 | break; | ||
| 10507 | } | ||
| 10508 | } break; | ||
| 10509 | case TypeTableEntryIdVoid: | ||
| 10510 | case TypeTableEntryIdBool: | ||
| 10511 | case TypeTableEntryIdInt: | ||
| 10512 | case TypeTableEntryIdFloat: | ||
| 10513 | case TypeTableEntryIdPointer: | ||
| 10514 | case TypeTableEntryIdArray: | ||
| 10515 | case TypeTableEntryIdNumLitFloat: | ||
| 10516 | case TypeTableEntryIdNumLitInt: | ||
| 10517 | case TypeTableEntryIdUndefLit: | ||
| 10518 | case TypeTableEntryIdNullLit: | ||
| 10519 | case TypeTableEntryIdMaybe: | ||
| 10520 | case TypeTableEntryIdErrorUnion: | ||
| 10521 | case TypeTableEntryIdPureError: | ||
| 10522 | zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); | ||
| 10523 | case TypeTableEntryIdNamespace: | ||
| 10524 | case TypeTableEntryIdBlock: | ||
| 10525 | case TypeTableEntryIdBoundFn: | ||
| 10526 | case TypeTableEntryIdArgTuple: | ||
| 10527 | case TypeTableEntryIdOpaque: | ||
| 10528 | ir_add_error(ira, target, | ||
| 10529 | buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name))); | ||
| 10530 | break; | ||
| 10531 | } | ||
| 10532 | |||
| 10533 | ir_build_const_from(ira, &instruction->base); | ||
| 10534 | return ira->codegen->builtin_types.entry_void; | ||
| 10535 | } | ||
| 10536 | |||
| 10268 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, | 10537 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| 10269 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) | 10538 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) |
| 10270 | { | 10539 | { |
| ... | @@ -10442,7 +10711,7 @@ no_mem_slot: | ... | @@ -10442,7 +10711,7 @@ no_mem_slot: |
| 10442 | 10711 | ||
| 10443 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, | 10712 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, |
| 10444 | FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref, | 10713 | FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref, |
| 10445 | IrInstruction *first_arg_ptr, bool comptime_fn_call, bool inline_fn_call) | 10714 | IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) |
| 10446 | { | 10715 | { |
| 10447 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; | 10716 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| 10448 | size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; | 10717 | size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; |
| ... | @@ -10701,7 +10970,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -10701,7 +10970,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10701 | 10970 | ||
| 10702 | if (type_requires_comptime(return_type)) { | 10971 | if (type_requires_comptime(return_type)) { |
| 10703 | // Throw out our work and call the function as if it were comptime. | 10972 | // Throw out our work and call the function as if it were comptime. |
| 10704 | return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, false); | 10973 | return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto); |
| 10705 | } | 10974 | } |
| 10706 | } | 10975 | } |
| 10707 | 10976 | ||
| ... | @@ -10725,7 +10994,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -10725,7 +10994,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10725 | 10994 | ||
| 10726 | size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; | 10995 | size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; |
| 10727 | IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, | 10996 | IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, |
| 10728 | impl_fn, nullptr, impl_param_count, casted_args, false, inline_fn_call); | 10997 | impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline); |
| 10729 | 10998 | ||
| 10730 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; | 10999 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; |
| 10731 | ir_add_alloca(ira, new_call_instruction, return_type); | 11000 | ir_add_alloca(ira, new_call_instruction, return_type); |
| ... | @@ -10784,7 +11053,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -10784,7 +11053,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10784 | return ira->codegen->builtin_types.entry_invalid; | 11053 | return ira->codegen->builtin_types.entry_invalid; |
| 10785 | 11054 | ||
| 10786 | IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, | 11055 | IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, |
| 10787 | fn_entry, fn_ref, call_param_count, casted_args, false, inline_fn_call); | 11056 | fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline); |
| 10788 | 11057 | ||
| 10789 | ir_add_alloca(ira, new_call_instruction, return_type); | 11058 | ir_add_alloca(ira, new_call_instruction, return_type); |
| 10790 | return ir_finish_anal(ira, return_type); | 11059 | return ir_finish_anal(ira, return_type); |
| ... | @@ -10823,13 +11092,13 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction | ... | @@ -10823,13 +11092,13 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 10823 | } else if (fn_ref->value.type->id == TypeTableEntryIdFn) { | 11092 | } else if (fn_ref->value.type->id == TypeTableEntryIdFn) { |
| 10824 | FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref); | 11093 | FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref); |
| 10825 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, | 11094 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, |
| 10826 | fn_ref, nullptr, is_comptime, call_instruction->is_inline); | 11095 | fn_ref, nullptr, is_comptime, call_instruction->fn_inline); |
| 10827 | } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) { | 11096 | } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) { |
| 10828 | assert(fn_ref->value.special == ConstValSpecialStatic); | 11097 | assert(fn_ref->value.special == ConstValSpecialStatic); |
| 10829 | FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn; | 11098 | FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn; |
| 10830 | IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg; | 11099 | IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg; |
| 10831 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, | 11100 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, |
| 10832 | nullptr, first_arg_ptr, is_comptime, call_instruction->is_inline); | 11101 | nullptr, first_arg_ptr, is_comptime, call_instruction->fn_inline); |
| 10833 | } else { | 11102 | } else { |
| 10834 | ir_add_error_node(ira, fn_ref->source_node, | 11103 | ir_add_error_node(ira, fn_ref->source_node, |
| 10835 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name))); | 11104 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name))); |
| ... | @@ -10839,7 +11108,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction | ... | @@ -10839,7 +11108,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 10839 | 11108 | ||
| 10840 | if (fn_ref->value.type->id == TypeTableEntryIdFn) { | 11109 | if (fn_ref->value.type->id == TypeTableEntryIdFn) { |
| 10841 | return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->value.type, | 11110 | return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->value.type, |
| 10842 | fn_ref, nullptr, false, false); | 11111 | fn_ref, nullptr, false, FnInlineAuto); |
| 10843 | } else { | 11112 | } else { |
| 10844 | ir_add_error_node(ira, fn_ref->source_node, | 11113 | ir_add_error_node(ira, fn_ref->source_node, |
| 10845 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name))); | 11114 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name))); |
| ... | @@ -12183,102 +12452,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, | ... | @@ -12183,102 +12452,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, |
| 12183 | return ira->codegen->builtin_types.entry_type; | 12452 | return ira->codegen->builtin_types.entry_type; |
| 12184 | } | 12453 | } |
| 12185 | 12454 | ||
| 12186 | static TypeTableEntry *ir_analyze_instruction_set_global_section(IrAnalyze *ira, | ||
| 12187 | IrInstructionSetGlobalSection *instruction) | ||
| 12188 | { | ||
| 12189 | Tld *tld = instruction->tld; | ||
| 12190 | IrInstruction *section_value = instruction->value->other; | ||
| 12191 | |||
| 12192 | resolve_top_level_decl(ira->codegen, tld, true, instruction->base.source_node); | ||
| 12193 | if (tld->resolution == TldResolutionInvalid) | ||
| 12194 | return ira->codegen->builtin_types.entry_invalid; | ||
| 12195 | |||
| 12196 | Buf *section_name = ir_resolve_str(ira, section_value); | ||
| 12197 | if (!section_name) | ||
| 12198 | return ira->codegen->builtin_types.entry_invalid; | ||
| 12199 | |||
| 12200 | AstNode **set_global_section_node; | ||
| 12201 | Buf **section_name_ptr; | ||
| 12202 | if (tld->id == TldIdVar) { | ||
| 12203 | TldVar *tld_var = (TldVar *)tld; | ||
| 12204 | set_global_section_node = &tld_var->set_global_section_node; | ||
| 12205 | section_name_ptr = &tld_var->section_name; | ||
| 12206 | |||
| 12207 | if (tld_var->var->linkage == VarLinkageExternal) { | ||
| 12208 | ErrorMsg *msg = ir_add_error(ira, &instruction->base, | ||
| 12209 | buf_sprintf("cannot set section of external variable '%s'", buf_ptr(&tld_var->var->name))); | ||
| 12210 | add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); | ||
| 12211 | return ira->codegen->builtin_types.entry_invalid; | ||
| 12212 | } | ||
| 12213 | } else if (tld->id == TldIdFn) { | ||
| 12214 | TldFn *tld_fn = (TldFn *)tld; | ||
| 12215 | FnTableEntry *fn_entry = tld_fn->fn_entry; | ||
| 12216 | set_global_section_node = &fn_entry->set_global_section_node; | ||
| 12217 | section_name_ptr = &fn_entry->section_name; | ||
| 12218 | |||
| 12219 | if (fn_entry->def_scope == nullptr) { | ||
| 12220 | ErrorMsg *msg = ir_add_error(ira, &instruction->base, | ||
| 12221 | buf_sprintf("cannot set section of external function '%s'", buf_ptr(&fn_entry->symbol_name))); | ||
| 12222 | add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); | ||
| 12223 | return ira->codegen->builtin_types.entry_invalid; | ||
| 12224 | } | ||
| 12225 | } else { | ||
| 12226 | // error is caught in pass1 IR gen | ||
| 12227 | zig_unreachable(); | ||
| 12228 | } | ||
| 12229 | |||
| 12230 | AstNode *source_node = instruction->base.source_node; | ||
| 12231 | if (*set_global_section_node) { | ||
| 12232 | ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("section set twice")); | ||
| 12233 | add_error_note(ira->codegen, msg, *set_global_section_node, buf_sprintf("first set here")); | ||
| 12234 | return ira->codegen->builtin_types.entry_invalid; | ||
| 12235 | } | ||
| 12236 | *set_global_section_node = source_node; | ||
| 12237 | *section_name_ptr = section_name; | ||
| 12238 | |||
| 12239 | ir_build_const_from(ira, &instruction->base); | ||
| 12240 | return ira->codegen->builtin_types.entry_void; | ||
| 12241 | } | ||
| 12242 | |||
| 12243 | static TypeTableEntry *ir_analyze_instruction_set_global_linkage(IrAnalyze *ira, | ||
| 12244 | IrInstructionSetGlobalLinkage *instruction) | ||
| 12245 | { | ||
| 12246 | Tld *tld = instruction->tld; | ||
| 12247 | IrInstruction *linkage_value = instruction->value->other; | ||
| 12248 | |||
| 12249 | GlobalLinkageId linkage_scalar; | ||
| 12250 | if (!ir_resolve_global_linkage(ira, linkage_value, &linkage_scalar)) | ||
| 12251 | return ira->codegen->builtin_types.entry_invalid; | ||
| 12252 | |||
| 12253 | AstNode **set_global_linkage_node; | ||
| 12254 | GlobalLinkageId *dest_linkage_ptr; | ||
| 12255 | if (tld->id == TldIdVar) { | ||
| 12256 | TldVar *tld_var = (TldVar *)tld; | ||
| 12257 | set_global_linkage_node = &tld_var->set_global_linkage_node; | ||
| 12258 | dest_linkage_ptr = &tld_var->linkage; | ||
| 12259 | } else if (tld->id == TldIdFn) { | ||
| 12260 | TldFn *tld_fn = (TldFn *)tld; | ||
| 12261 | FnTableEntry *fn_entry = tld_fn->fn_entry; | ||
| 12262 | set_global_linkage_node = &fn_entry->set_global_linkage_node; | ||
| 12263 | dest_linkage_ptr = &fn_entry->linkage; | ||
| 12264 | } else { | ||
| 12265 | // error is caught in pass1 IR gen | ||
| 12266 | zig_unreachable(); | ||
| 12267 | } | ||
| 12268 | |||
| 12269 | AstNode *source_node = instruction->base.source_node; | ||
| 12270 | if (*set_global_linkage_node) { | ||
| 12271 | ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("linkage set twice")); | ||
| 12272 | add_error_note(ira->codegen, msg, *set_global_linkage_node, buf_sprintf("first set here")); | ||
| 12273 | return ira->codegen->builtin_types.entry_invalid; | ||
| 12274 | } | ||
| 12275 | *set_global_linkage_node = source_node; | ||
| 12276 | *dest_linkage_ptr = linkage_scalar; | ||
| 12277 | |||
| 12278 | ir_build_const_from(ira, &instruction->base); | ||
| 12279 | return ira->codegen->builtin_types.entry_void; | ||
| 12280 | } | ||
| 12281 | |||
| 12282 | static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, | 12455 | static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, |
| 12283 | IrInstructionSetDebugSafety *set_debug_safety_instruction) | 12456 | IrInstructionSetDebugSafety *set_debug_safety_instruction) |
| 12284 | { | 12457 | { |
| ... | @@ -12999,6 +13172,16 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -12999,6 +13172,16 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 12999 | return tag_type; | 13172 | return tag_type; |
| 13000 | } | 13173 | } |
| 13001 | case TypeTableEntryIdEnum: { | 13174 | case TypeTableEntryIdEnum: { |
| 13175 | type_ensure_zero_bits_known(ira->codegen, target_type); | ||
| 13176 | if (type_is_invalid(target_type)) | ||
| 13177 | return ira->codegen->builtin_types.entry_invalid; | ||
| 13178 | if (target_type->data.enumeration.src_field_count < 2) { | ||
| 13179 | TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; | ||
| 13180 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); | ||
| 13181 | bigint_init_bigint(&out_val->data.x_enum_tag, &only_field->value); | ||
| 13182 | return target_type; | ||
| 13183 | } | ||
| 13184 | |||
| 13002 | if (pointee_val) { | 13185 | if (pointee_val) { |
| 13003 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); | 13186 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); |
| 13004 | bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_enum_tag); | 13187 | bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_enum_tag); |
| ... | @@ -13865,6 +14048,9 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc | ... | @@ -13865,6 +14048,9 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc |
| 13865 | ImportTableEntry *child_import = allocate<ImportTableEntry>(1); | 14048 | ImportTableEntry *child_import = allocate<ImportTableEntry>(1); |
| 13866 | child_import->decls_scope = create_decls_scope(node, nullptr, nullptr, child_import); | 14049 | child_import->decls_scope = create_decls_scope(node, nullptr, nullptr, child_import); |
| 13867 | child_import->c_import_node = node; | 14050 | child_import->c_import_node = node; |
| 14051 | child_import->package = new_anonymous_package(); | ||
| 14052 | child_import->package->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package); | ||
| 14053 | child_import->package->package_table.put(buf_create_from_str("std"), ira->codegen->std_package); | ||
| 13868 | 14054 | ||
| 13869 | ZigList<ErrorMsg *> errors = {0}; | 14055 | ZigList<ErrorMsg *> errors = {0}; |
| 13870 | 14056 | ||
| ... | @@ -15735,8 +15921,12 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_of(IrAnalyze *ira, IrInst | ... | @@ -15735,8 +15921,12 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_of(IrAnalyze *ira, IrInst |
| 15735 | return ira->codegen->builtin_types.entry_invalid; | 15921 | return ira->codegen->builtin_types.entry_invalid; |
| 15736 | 15922 | ||
| 15737 | uint32_t align_bytes; | 15923 | uint32_t align_bytes; |
| 15738 | if (!ir_resolve_align(ira, instruction->align_value->other, &align_bytes)) | 15924 | if (instruction->align_value != nullptr) { |
| 15739 | return ira->codegen->builtin_types.entry_invalid; | 15925 | if (!ir_resolve_align(ira, instruction->align_value->other, &align_bytes)) |
| 15926 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15927 | } else { | ||
| 15928 | align_bytes = get_abi_alignment(ira->codegen, child_type); | ||
| 15929 | } | ||
| 15740 | 15930 | ||
| 15741 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | 15931 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 15742 | out_val->data.x_type = get_pointer_to_type_extra(ira->codegen, child_type, | 15932 | out_val->data.x_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| ... | @@ -15932,10 +16122,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -15932,10 +16122,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15932 | return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction); | 16122 | return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction); |
| 15933 | case IrInstructionIdPtrTypeChild: | 16123 | case IrInstructionIdPtrTypeChild: |
| 15934 | return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); | 16124 | return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); |
| 15935 | case IrInstructionIdSetGlobalSection: | ||
| 15936 | return ir_analyze_instruction_set_global_section(ira, (IrInstructionSetGlobalSection *)instruction); | ||
| 15937 | case IrInstructionIdSetGlobalLinkage: | ||
| 15938 | return ir_analyze_instruction_set_global_linkage(ira, (IrInstructionSetGlobalLinkage *)instruction); | ||
| 15939 | case IrInstructionIdSetDebugSafety: | 16125 | case IrInstructionIdSetDebugSafety: |
| 15940 | return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction); | 16126 | return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction); |
| 15941 | case IrInstructionIdSetFloatMode: | 16127 | case IrInstructionIdSetFloatMode: |
| ... | @@ -16078,6 +16264,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -16078,6 +16264,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 16078 | return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction); | 16264 | return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction); |
| 16079 | case IrInstructionIdTagType: | 16265 | case IrInstructionIdTagType: |
| 16080 | return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction); | 16266 | return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction); |
| 16267 | case IrInstructionIdExport: | ||
| 16268 | return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction); | ||
| 16081 | } | 16269 | } |
| 16082 | zig_unreachable(); | 16270 | zig_unreachable(); |
| 16083 | } | 16271 | } |
| ... | @@ -16185,12 +16373,11 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -16185,12 +16373,11 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 16185 | case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free | 16373 | case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free |
| 16186 | case IrInstructionIdCheckSwitchProngs: | 16374 | case IrInstructionIdCheckSwitchProngs: |
| 16187 | case IrInstructionIdCheckStatementIsVoid: | 16375 | case IrInstructionIdCheckStatementIsVoid: |
| 16188 | case IrInstructionIdSetGlobalSection: | ||
| 16189 | case IrInstructionIdSetGlobalLinkage: | ||
| 16190 | case IrInstructionIdPanic: | 16376 | case IrInstructionIdPanic: |
| 16191 | case IrInstructionIdSetEvalBranchQuota: | 16377 | case IrInstructionIdSetEvalBranchQuota: |
| 16192 | case IrInstructionIdPtrTypeOf: | 16378 | case IrInstructionIdPtrTypeOf: |
| 16193 | case IrInstructionIdSetAlignStack: | 16379 | case IrInstructionIdSetAlignStack: |
| 16380 | case IrInstructionIdExport: | ||
| 16194 | return true; | 16381 | return true; |
| 16195 | case IrInstructionIdPhi: | 16382 | case IrInstructionIdPhi: |
| 16196 | case IrInstructionIdUnOp: | 16383 | case IrInstructionIdUnOp: |
src/ir_print.cpp+27-21| ... | @@ -886,8 +886,12 @@ static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCas | ... | @@ -886,8 +886,12 @@ static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCas |
| 886 | } | 886 | } |
| 887 | 887 | ||
| 888 | static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instruction) { | 888 | static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instruction) { |
| 889 | fprintf(irp->f, "&align "); | 889 | fprintf(irp->f, "&"); |
| 890 | ir_print_other_instruction(irp, instruction->align_value); | 890 | if (instruction->align_value != nullptr) { |
| 891 | fprintf(irp->f, "align("); | ||
| 892 | ir_print_other_instruction(irp, instruction->align_value); | ||
| 893 | fprintf(irp->f, ")"); | ||
| 894 | } | ||
| 891 | const char *const_str = instruction->is_const ? "const " : ""; | 895 | const char *const_str = instruction->is_const ? "const " : ""; |
| 892 | const char *volatile_str = instruction->is_volatile ? "volatile " : ""; | 896 | const char *volatile_str = instruction->is_volatile ? "volatile " : ""; |
| 893 | fprintf(irp->f, ":%" PRIu32 ":%" PRIu32 " %s%s", instruction->bit_offset_start, instruction->bit_offset_end, | 897 | fprintf(irp->f, ":%" PRIu32 ":%" PRIu32 " %s%s", instruction->bit_offset_start, instruction->bit_offset_end, |
| ... | @@ -895,19 +899,6 @@ static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instructi | ... | @@ -895,19 +899,6 @@ static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instructi |
| 895 | ir_print_other_instruction(irp, instruction->child_type); | 899 | ir_print_other_instruction(irp, instruction->child_type); |
| 896 | } | 900 | } |
| 897 | 901 | ||
| 898 | static void ir_print_set_global_section(IrPrint *irp, IrInstructionSetGlobalSection *instruction) { | ||
| 899 | fprintf(irp->f, "@setGlobalSection(%s,", buf_ptr(instruction->tld->name)); | ||
| 900 | ir_print_other_instruction(irp, instruction->value); | ||
| 901 | fprintf(irp->f, ")"); | ||
| 902 | } | ||
| 903 | |||
| 904 | static void ir_print_set_global_linkage(IrPrint *irp, IrInstructionSetGlobalLinkage *instruction) { | ||
| 905 | fprintf(irp->f, "@setGlobalLinkage(%s,", buf_ptr(instruction->tld->name)); | ||
| 906 | ir_print_other_instruction(irp, instruction->value); | ||
| 907 | fprintf(irp->f, ")"); | ||
| 908 | } | ||
| 909 | |||
| 910 | |||
| 911 | static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) { | 902 | static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) { |
| 912 | const char *ptr_str = instruction->lval.is_ptr ? "ptr " : ""; | 903 | const char *ptr_str = instruction->lval.is_ptr ? "ptr " : ""; |
| 913 | const char *const_str = instruction->lval.is_const ? "const " : ""; | 904 | const char *const_str = instruction->lval.is_const ? "const " : ""; |
| ... | @@ -987,6 +978,24 @@ static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instructi | ... | @@ -987,6 +978,24 @@ static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instructi |
| 987 | fprintf(irp->f, ")"); | 978 | fprintf(irp->f, ")"); |
| 988 | } | 979 | } |
| 989 | 980 | ||
| 981 | static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) { | ||
| 982 | if (instruction->linkage == nullptr) { | ||
| 983 | fprintf(irp->f, "@export("); | ||
| 984 | ir_print_other_instruction(irp, instruction->name); | ||
| 985 | fprintf(irp->f, ","); | ||
| 986 | ir_print_other_instruction(irp, instruction->target); | ||
| 987 | fprintf(irp->f, ")"); | ||
| 988 | } else { | ||
| 989 | fprintf(irp->f, "@exportWithLinkage("); | ||
| 990 | ir_print_other_instruction(irp, instruction->name); | ||
| 991 | fprintf(irp->f, ","); | ||
| 992 | ir_print_other_instruction(irp, instruction->target); | ||
| 993 | fprintf(irp->f, ","); | ||
| 994 | ir_print_other_instruction(irp, instruction->linkage); | ||
| 995 | fprintf(irp->f, ")"); | ||
| 996 | } | ||
| 997 | } | ||
| 998 | |||
| 990 | 999 | ||
| 991 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 1000 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 992 | ir_print_prefix(irp, instruction); | 1001 | ir_print_prefix(irp, instruction); |
| ... | @@ -1263,12 +1272,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1263,12 +1272,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1263 | case IrInstructionIdPtrTypeOf: | 1272 | case IrInstructionIdPtrTypeOf: |
| 1264 | ir_print_ptr_type_of(irp, (IrInstructionPtrTypeOf *)instruction); | 1273 | ir_print_ptr_type_of(irp, (IrInstructionPtrTypeOf *)instruction); |
| 1265 | break; | 1274 | break; |
| 1266 | case IrInstructionIdSetGlobalSection: | ||
| 1267 | ir_print_set_global_section(irp, (IrInstructionSetGlobalSection *)instruction); | ||
| 1268 | break; | ||
| 1269 | case IrInstructionIdSetGlobalLinkage: | ||
| 1270 | ir_print_set_global_linkage(irp, (IrInstructionSetGlobalLinkage *)instruction); | ||
| 1271 | break; | ||
| 1272 | case IrInstructionIdDeclRef: | 1275 | case IrInstructionIdDeclRef: |
| 1273 | ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction); | 1276 | ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction); |
| 1274 | break; | 1277 | break; |
| ... | @@ -1302,6 +1305,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1302,6 +1305,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1302 | case IrInstructionIdTagType: | 1305 | case IrInstructionIdTagType: |
| 1303 | ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction); | 1306 | ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction); |
| 1304 | break; | 1307 | break; |
| 1308 | case IrInstructionIdExport: | ||
| 1309 | ir_print_export(irp, (IrInstructionExport *)instruction); | ||
| 1310 | break; | ||
| 1305 | } | 1311 | } |
| 1306 | fprintf(irp->f, "\n"); | 1312 | fprintf(irp->f, "\n"); |
| 1307 | } | 1313 | } |
src/parser.cpp+236-179| ... | @@ -632,27 +632,6 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m | ... | @@ -632,27 +632,6 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m |
| 632 | return node; | 632 | return node; |
| 633 | } | 633 | } |
| 634 | 634 | ||
| 635 | /* | ||
| 636 | GotoExpression = "goto" Symbol | ||
| 637 | */ | ||
| 638 | static AstNode *ast_parse_goto_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | ||
| 639 | Token *goto_token = &pc->tokens->at(*token_index); | ||
| 640 | if (goto_token->id == TokenIdKeywordGoto) { | ||
| 641 | *token_index += 1; | ||
| 642 | } else if (mandatory) { | ||
| 643 | ast_expect_token(pc, goto_token, TokenIdKeywordGoto); | ||
| 644 | zig_unreachable(); | ||
| 645 | } else { | ||
| 646 | return nullptr; | ||
| 647 | } | ||
| 648 | |||
| 649 | AstNode *node = ast_create_node(pc, NodeTypeGoto, goto_token); | ||
| 650 | |||
| 651 | Token *dest_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 652 | node->data.goto_expr.name = token_buf(dest_symbol); | ||
| 653 | return node; | ||
| 654 | } | ||
| 655 | |||
| 656 | /* | 635 | /* |
| 657 | CompTimeExpression(body) = "comptime" body | 636 | CompTimeExpression(body) = "comptime" body |
| 658 | */ | 637 | */ |
| ... | @@ -676,8 +655,8 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b | ... | @@ -676,8 +655,8 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b |
| 676 | } | 655 | } |
| 677 | 656 | ||
| 678 | /* | 657 | /* |
| 679 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | 658 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol)) |
| 680 | KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable" | 659 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" |
| 681 | */ | 660 | */ |
| 682 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | 661 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 683 | Token *token = &pc->tokens->at(*token_index); | 662 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -721,6 +700,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo | ... | @@ -721,6 +700,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo |
| 721 | } else if (token->id == TokenIdKeywordContinue) { | 700 | } else if (token->id == TokenIdKeywordContinue) { |
| 722 | AstNode *node = ast_create_node(pc, NodeTypeContinue, token); | 701 | AstNode *node = ast_create_node(pc, NodeTypeContinue, token); |
| 723 | *token_index += 1; | 702 | *token_index += 1; |
| 703 | Token *maybe_colon_token = &pc->tokens->at(*token_index); | ||
| 704 | if (maybe_colon_token->id == TokenIdColon) { | ||
| 705 | *token_index += 1; | ||
| 706 | Token *name = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 707 | node->data.continue_expr.name = token_buf(name); | ||
| 708 | } | ||
| 724 | return node; | 709 | return node; |
| 725 | } else if (token->id == TokenIdKeywordUndefined) { | 710 | } else if (token->id == TokenIdKeywordUndefined) { |
| 726 | AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token); | 711 | AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token); |
| ... | @@ -740,9 +725,21 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo | ... | @@ -740,9 +725,21 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo |
| 740 | return node; | 725 | return node; |
| 741 | } else if (token->id == TokenIdAtSign) { | 726 | } else if (token->id == TokenIdAtSign) { |
| 742 | *token_index += 1; | 727 | *token_index += 1; |
| 743 | Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); | 728 | Token *name_tok = &pc->tokens->at(*token_index); |
| 729 | Buf *name_buf; | ||
| 730 | if (name_tok->id == TokenIdKeywordExport) { | ||
| 731 | name_buf = buf_create_from_str("export"); | ||
| 732 | *token_index += 1; | ||
| 733 | } else if (name_tok->id == TokenIdSymbol) { | ||
| 734 | name_buf = token_buf(name_tok); | ||
| 735 | *token_index += 1; | ||
| 736 | } else { | ||
| 737 | ast_expect_token(pc, name_tok, TokenIdSymbol); | ||
| 738 | zig_unreachable(); | ||
| 739 | } | ||
| 740 | |||
| 744 | AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok); | 741 | AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok); |
| 745 | name_node->data.symbol_expr.symbol = token_buf(name_tok); | 742 | name_node->data.symbol_expr.symbol = name_buf; |
| 746 | 743 | ||
| 747 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); | 744 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); |
| 748 | node->data.fn_call_expr.fn_ref_expr = name_node; | 745 | node->data.fn_call_expr.fn_ref_expr = name_node; |
| ... | @@ -751,27 +748,25 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo | ... | @@ -751,27 +748,25 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo |
| 751 | node->data.fn_call_expr.is_builtin = true; | 748 | node->data.fn_call_expr.is_builtin = true; |
| 752 | 749 | ||
| 753 | return node; | 750 | return node; |
| 754 | } else if (token->id == TokenIdSymbol) { | 751 | } |
| 752 | |||
| 753 | AstNode *block_expr_node = ast_parse_block_expr(pc, token_index, false); | ||
| 754 | if (block_expr_node) { | ||
| 755 | return block_expr_node; | ||
| 756 | } | ||
| 757 | |||
| 758 | if (token->id == TokenIdSymbol) { | ||
| 755 | *token_index += 1; | 759 | *token_index += 1; |
| 756 | AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); | 760 | AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); |
| 757 | node->data.symbol_expr.symbol = token_buf(token); | 761 | node->data.symbol_expr.symbol = token_buf(token); |
| 758 | return node; | 762 | return node; |
| 759 | } | 763 | } |
| 760 | 764 | ||
| 761 | AstNode *goto_node = ast_parse_goto_expr(pc, token_index, false); | ||
| 762 | if (goto_node) | ||
| 763 | return goto_node; | ||
| 764 | |||
| 765 | AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false); | 765 | AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false); |
| 766 | if (grouped_expr_node) { | 766 | if (grouped_expr_node) { |
| 767 | return grouped_expr_node; | 767 | return grouped_expr_node; |
| 768 | } | 768 | } |
| 769 | 769 | ||
| 770 | AstNode *block_expr_node = ast_parse_block_expr(pc, token_index, false); | ||
| 771 | if (block_expr_node) { | ||
| 772 | return block_expr_node; | ||
| 773 | } | ||
| 774 | |||
| 775 | AstNode *array_type_node = ast_parse_array_type_expr(pc, token_index, false); | 770 | AstNode *array_type_node = ast_parse_array_type_expr(pc, token_index, false); |
| 776 | if (array_type_node) { | 771 | if (array_type_node) { |
| 777 | return array_type_node; | 772 | return array_type_node; |
| ... | @@ -791,13 +786,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo | ... | @@ -791,13 +786,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo |
| 791 | if (container_decl) | 786 | if (container_decl) |
| 792 | return container_decl; | 787 | return container_decl; |
| 793 | 788 | ||
| 794 | if (token->id == TokenIdKeywordExtern) { | ||
| 795 | *token_index += 1; | ||
| 796 | AstNode *node = ast_parse_fn_proto(pc, token_index, true, VisibModPrivate); | ||
| 797 | node->data.fn_proto.is_extern = true; | ||
| 798 | return node; | ||
| 799 | } | ||
| 800 | |||
| 801 | if (!mandatory) | 789 | if (!mandatory) |
| 802 | return nullptr; | 790 | return nullptr; |
| 803 | 791 | ||
| ... | @@ -1483,7 +1471,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) { | ... | @@ -1483,7 +1471,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) { |
| 1483 | } | 1471 | } |
| 1484 | 1472 | ||
| 1485 | /* | 1473 | /* |
| 1486 | BreakExpression : "break" option(Expression) | 1474 | BreakExpression = "break" option(":" Symbol) option(Expression) |
| 1487 | */ | 1475 | */ |
| 1488 | static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) { | 1476 | static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) { |
| 1489 | Token *token = &pc->tokens->at(*token_index); | 1477 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -1493,8 +1481,15 @@ static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) { | ... | @@ -1493,8 +1481,15 @@ static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) { |
| 1493 | } else { | 1481 | } else { |
| 1494 | return nullptr; | 1482 | return nullptr; |
| 1495 | } | 1483 | } |
| 1496 | |||
| 1497 | AstNode *node = ast_create_node(pc, NodeTypeBreak, token); | 1484 | AstNode *node = ast_create_node(pc, NodeTypeBreak, token); |
| 1485 | |||
| 1486 | Token *maybe_colon_token = &pc->tokens->at(*token_index); | ||
| 1487 | if (maybe_colon_token->id == TokenIdColon) { | ||
| 1488 | *token_index += 1; | ||
| 1489 | Token *name = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 1490 | node->data.break_expr.name = token_buf(name); | ||
| 1491 | } | ||
| 1492 | |||
| 1498 | node->data.break_expr.expr = ast_parse_expression(pc, token_index, false); | 1493 | node->data.break_expr.expr = ast_parse_expression(pc, token_index, false); |
| 1499 | 1494 | ||
| 1500 | return node; | 1495 | return node; |
| ... | @@ -1534,38 +1529,20 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) { | ... | @@ -1534,38 +1529,20 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) { |
| 1534 | } | 1529 | } |
| 1535 | 1530 | ||
| 1536 | /* | 1531 | /* |
| 1537 | VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression | 1532 | VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression |
| 1538 | */ | 1533 | */ |
| 1539 | static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory, | 1534 | static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory, |
| 1540 | VisibMod visib_mod) | 1535 | VisibMod visib_mod, bool is_comptime, bool is_export) |
| 1541 | { | 1536 | { |
| 1542 | Token *first_token = &pc->tokens->at(*token_index); | 1537 | Token *first_token = &pc->tokens->at(*token_index); |
| 1543 | Token *var_token; | 1538 | Token *var_token; |
| 1544 | 1539 | ||
| 1545 | bool is_const; | 1540 | bool is_const; |
| 1546 | bool is_comptime; | 1541 | if (first_token->id == TokenIdKeywordVar) { |
| 1547 | if (first_token->id == TokenIdKeywordCompTime) { | ||
| 1548 | is_comptime = true; | ||
| 1549 | var_token = &pc->tokens->at(*token_index + 1); | ||
| 1550 | |||
| 1551 | if (var_token->id == TokenIdKeywordVar) { | ||
| 1552 | is_const = false; | ||
| 1553 | } else if (var_token->id == TokenIdKeywordConst) { | ||
| 1554 | is_const = true; | ||
| 1555 | } else if (mandatory) { | ||
| 1556 | ast_invalid_token_error(pc, var_token); | ||
| 1557 | } else { | ||
| 1558 | return nullptr; | ||
| 1559 | } | ||
| 1560 | |||
| 1561 | *token_index += 2; | ||
| 1562 | } else if (first_token->id == TokenIdKeywordVar) { | ||
| 1563 | is_comptime = false; | ||
| 1564 | is_const = false; | 1542 | is_const = false; |
| 1565 | var_token = first_token; | 1543 | var_token = first_token; |
| 1566 | *token_index += 1; | 1544 | *token_index += 1; |
| 1567 | } else if (first_token->id == TokenIdKeywordConst) { | 1545 | } else if (first_token->id == TokenIdKeywordConst) { |
| 1568 | is_comptime = false; | ||
| 1569 | is_const = true; | 1546 | is_const = true; |
| 1570 | var_token = first_token; | 1547 | var_token = first_token; |
| 1571 | *token_index += 1; | 1548 | *token_index += 1; |
| ... | @@ -1577,7 +1554,8 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to | ... | @@ -1577,7 +1554,8 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to |
| 1577 | 1554 | ||
| 1578 | AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_token); | 1555 | AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_token); |
| 1579 | 1556 | ||
| 1580 | node->data.variable_declaration.is_inline = is_comptime; | 1557 | node->data.variable_declaration.is_comptime = is_comptime; |
| 1558 | node->data.variable_declaration.is_export = is_export; | ||
| 1581 | node->data.variable_declaration.is_const = is_const; | 1559 | node->data.variable_declaration.is_const = is_const; |
| 1582 | node->data.variable_declaration.visib_mod = visib_mod; | 1560 | node->data.variable_declaration.visib_mod = visib_mod; |
| 1583 | 1561 | ||
| ... | @@ -1600,6 +1578,14 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to | ... | @@ -1600,6 +1578,14 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to |
| 1600 | next_token = &pc->tokens->at(*token_index); | 1578 | next_token = &pc->tokens->at(*token_index); |
| 1601 | } | 1579 | } |
| 1602 | 1580 | ||
| 1581 | if (next_token->id == TokenIdKeywordSection) { | ||
| 1582 | *token_index += 1; | ||
| 1583 | ast_eat_token(pc, token_index, TokenIdLParen); | ||
| 1584 | node->data.variable_declaration.section_expr = ast_parse_expression(pc, token_index, true); | ||
| 1585 | ast_eat_token(pc, token_index, TokenIdRParen); | ||
| 1586 | next_token = &pc->tokens->at(*token_index); | ||
| 1587 | } | ||
| 1588 | |||
| 1603 | if (next_token->id == TokenIdEq) { | 1589 | if (next_token->id == TokenIdEq) { |
| 1604 | *token_index += 1; | 1590 | *token_index += 1; |
| 1605 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); | 1591 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); |
| ... | @@ -1612,6 +1598,50 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to | ... | @@ -1612,6 +1598,50 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to |
| 1612 | return node; | 1598 | return node; |
| 1613 | } | 1599 | } |
| 1614 | 1600 | ||
| 1601 | /* | ||
| 1602 | GlobalVarDecl = option("export") VariableDeclaration ";" | ||
| 1603 | */ | ||
| 1604 | static AstNode *ast_parse_global_var_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) { | ||
| 1605 | Token *first_token = &pc->tokens->at(*token_index); | ||
| 1606 | |||
| 1607 | bool is_export = false;; | ||
| 1608 | if (first_token->id == TokenIdKeywordExport) { | ||
| 1609 | *token_index += 1; | ||
| 1610 | is_export = true; | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | AstNode *node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod, false, is_export); | ||
| 1614 | if (node == nullptr) { | ||
| 1615 | if (is_export) { | ||
| 1616 | *token_index -= 1; | ||
| 1617 | } | ||
| 1618 | return nullptr; | ||
| 1619 | } | ||
| 1620 | return node; | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | /* | ||
| 1624 | LocalVarDecl = option("comptime") VariableDeclaration | ||
| 1625 | */ | ||
| 1626 | static AstNode *ast_parse_local_var_decl(ParseContext *pc, size_t *token_index) { | ||
| 1627 | Token *first_token = &pc->tokens->at(*token_index); | ||
| 1628 | |||
| 1629 | bool is_comptime = false;; | ||
| 1630 | if (first_token->id == TokenIdKeywordCompTime) { | ||
| 1631 | *token_index += 1; | ||
| 1632 | is_comptime = true; | ||
| 1633 | } | ||
| 1634 | |||
| 1635 | AstNode *node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate, is_comptime, false); | ||
| 1636 | if (node == nullptr) { | ||
| 1637 | if (is_comptime) { | ||
| 1638 | *token_index -= 1; | ||
| 1639 | } | ||
| 1640 | return nullptr; | ||
| 1641 | } | ||
| 1642 | return node; | ||
| 1643 | } | ||
| 1644 | |||
| 1615 | /* | 1645 | /* |
| 1616 | BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression | 1646 | BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression |
| 1617 | */ | 1647 | */ |
| ... | @@ -1638,35 +1668,53 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, size_t *token_index, bo | ... | @@ -1638,35 +1668,53 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, size_t *token_index, bo |
| 1638 | } | 1668 | } |
| 1639 | 1669 | ||
| 1640 | /* | 1670 | /* |
| 1641 | WhileExpression(body) = option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body)) | 1671 | WhileExpression(body) = option(Symbol ":") option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body)) |
| 1642 | */ | 1672 | */ |
| 1643 | static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | 1673 | static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1644 | Token *first_token = &pc->tokens->at(*token_index); | 1674 | size_t orig_token_index = *token_index; |
| 1645 | Token *while_token; | ||
| 1646 | 1675 | ||
| 1647 | bool is_inline; | 1676 | Token *name_token = nullptr; |
| 1648 | if (first_token->id == TokenIdKeywordInline) { | 1677 | Token *token = &pc->tokens->at(*token_index); |
| 1649 | while_token = &pc->tokens->at(*token_index + 1); | 1678 | |
| 1650 | if (while_token->id == TokenIdKeywordWhile) { | 1679 | if (token->id == TokenIdSymbol) { |
| 1651 | is_inline = true; | 1680 | *token_index += 1; |
| 1652 | *token_index += 2; | 1681 | Token *colon_token = &pc->tokens->at(*token_index); |
| 1682 | if (colon_token->id == TokenIdColon) { | ||
| 1683 | *token_index += 1; | ||
| 1684 | name_token = token; | ||
| 1685 | token = &pc->tokens->at(*token_index); | ||
| 1653 | } else if (mandatory) { | 1686 | } else if (mandatory) { |
| 1654 | ast_expect_token(pc, while_token, TokenIdKeywordWhile); | 1687 | ast_expect_token(pc, colon_token, TokenIdColon); |
| 1655 | zig_unreachable(); | 1688 | zig_unreachable(); |
| 1656 | } else { | 1689 | } else { |
| 1690 | *token_index = orig_token_index; | ||
| 1657 | return nullptr; | 1691 | return nullptr; |
| 1658 | } | 1692 | } |
| 1659 | } else if (first_token->id == TokenIdKeywordWhile) { | 1693 | } |
| 1660 | while_token = first_token; | 1694 | |
| 1661 | is_inline = false; | 1695 | bool is_inline = false; |
| 1696 | if (token->id == TokenIdKeywordInline) { | ||
| 1697 | is_inline = true; | ||
| 1698 | *token_index += 1; | ||
| 1699 | token = &pc->tokens->at(*token_index); | ||
| 1700 | } | ||
| 1701 | |||
| 1702 | Token *while_token; | ||
| 1703 | if (token->id == TokenIdKeywordWhile) { | ||
| 1704 | while_token = token; | ||
| 1662 | *token_index += 1; | 1705 | *token_index += 1; |
| 1663 | } else if (mandatory) { | 1706 | } else if (mandatory) { |
| 1664 | ast_expect_token(pc, first_token, TokenIdKeywordWhile); | 1707 | ast_expect_token(pc, token, TokenIdKeywordWhile); |
| 1665 | zig_unreachable(); | 1708 | zig_unreachable(); |
| 1666 | } else { | 1709 | } else { |
| 1710 | *token_index = orig_token_index; | ||
| 1667 | return nullptr; | 1711 | return nullptr; |
| 1668 | } | 1712 | } |
| 1713 | |||
| 1669 | AstNode *node = ast_create_node(pc, NodeTypeWhileExpr, while_token); | 1714 | AstNode *node = ast_create_node(pc, NodeTypeWhileExpr, while_token); |
| 1715 | if (name_token != nullptr) { | ||
| 1716 | node->data.while_expr.name = token_buf(name_token); | ||
| 1717 | } | ||
| 1670 | node->data.while_expr.is_inline = is_inline; | 1718 | node->data.while_expr.is_inline = is_inline; |
| 1671 | 1719 | ||
| 1672 | ast_eat_token(pc, token_index, TokenIdLParen); | 1720 | ast_eat_token(pc, token_index, TokenIdLParen); |
| ... | @@ -1726,36 +1774,53 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) { | ... | @@ -1726,36 +1774,53 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) { |
| 1726 | } | 1774 | } |
| 1727 | 1775 | ||
| 1728 | /* | 1776 | /* |
| 1729 | ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body)) | 1777 | ForExpression(body) = option(Symbol ":") option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body)) |
| 1730 | */ | 1778 | */ |
| 1731 | static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | 1779 | static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1732 | Token *first_token = &pc->tokens->at(*token_index); | 1780 | size_t orig_token_index = *token_index; |
| 1733 | Token *for_token; | ||
| 1734 | 1781 | ||
| 1735 | bool is_inline; | 1782 | Token *name_token = nullptr; |
| 1736 | if (first_token->id == TokenIdKeywordInline) { | 1783 | Token *token = &pc->tokens->at(*token_index); |
| 1737 | is_inline = true; | 1784 | |
| 1738 | for_token = &pc->tokens->at(*token_index + 1); | 1785 | if (token->id == TokenIdSymbol) { |
| 1739 | if (for_token->id == TokenIdKeywordFor) { | 1786 | *token_index += 1; |
| 1740 | *token_index += 2; | 1787 | Token *colon_token = &pc->tokens->at(*token_index); |
| 1788 | if (colon_token->id == TokenIdColon) { | ||
| 1789 | *token_index += 1; | ||
| 1790 | name_token = token; | ||
| 1791 | token = &pc->tokens->at(*token_index); | ||
| 1741 | } else if (mandatory) { | 1792 | } else if (mandatory) { |
| 1742 | ast_expect_token(pc, first_token, TokenIdKeywordFor); | 1793 | ast_expect_token(pc, colon_token, TokenIdColon); |
| 1743 | zig_unreachable(); | 1794 | zig_unreachable(); |
| 1744 | } else { | 1795 | } else { |
| 1796 | *token_index = orig_token_index; | ||
| 1745 | return nullptr; | 1797 | return nullptr; |
| 1746 | } | 1798 | } |
| 1747 | } else if (first_token->id == TokenIdKeywordFor) { | 1799 | } |
| 1748 | for_token = first_token; | 1800 | |
| 1749 | is_inline = false; | 1801 | bool is_inline = false; |
| 1802 | if (token->id == TokenIdKeywordInline) { | ||
| 1803 | is_inline = true; | ||
| 1804 | *token_index += 1; | ||
| 1805 | token = &pc->tokens->at(*token_index); | ||
| 1806 | } | ||
| 1807 | |||
| 1808 | Token *for_token; | ||
| 1809 | if (token->id == TokenIdKeywordFor) { | ||
| 1810 | for_token = token; | ||
| 1750 | *token_index += 1; | 1811 | *token_index += 1; |
| 1751 | } else if (mandatory) { | 1812 | } else if (mandatory) { |
| 1752 | ast_expect_token(pc, first_token, TokenIdKeywordFor); | 1813 | ast_expect_token(pc, token, TokenIdKeywordFor); |
| 1753 | zig_unreachable(); | 1814 | zig_unreachable(); |
| 1754 | } else { | 1815 | } else { |
| 1816 | *token_index = orig_token_index; | ||
| 1755 | return nullptr; | 1817 | return nullptr; |
| 1756 | } | 1818 | } |
| 1757 | 1819 | ||
| 1758 | AstNode *node = ast_create_node(pc, NodeTypeForExpr, for_token); | 1820 | AstNode *node = ast_create_node(pc, NodeTypeForExpr, for_token); |
| 1821 | if (name_token != nullptr) { | ||
| 1822 | node->data.for_expr.name = token_buf(name_token); | ||
| 1823 | } | ||
| 1759 | node->data.for_expr.is_inline = is_inline; | 1824 | node->data.for_expr.is_inline = is_inline; |
| 1760 | 1825 | ||
| 1761 | ast_eat_token(pc, token_index, TokenIdLParen); | 1826 | ast_eat_token(pc, token_index, TokenIdLParen); |
| ... | @@ -2082,35 +2147,6 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool | ... | @@ -2082,35 +2147,6 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool |
| 2082 | return nullptr; | 2147 | return nullptr; |
| 2083 | } | 2148 | } |
| 2084 | 2149 | ||
| 2085 | /* | ||
| 2086 | Label: token(Symbol) token(Colon) | ||
| 2087 | */ | ||
| 2088 | static AstNode *ast_parse_label(ParseContext *pc, size_t *token_index, bool mandatory) { | ||
| 2089 | Token *symbol_token = &pc->tokens->at(*token_index); | ||
| 2090 | if (symbol_token->id != TokenIdSymbol) { | ||
| 2091 | if (mandatory) { | ||
| 2092 | ast_expect_token(pc, symbol_token, TokenIdSymbol); | ||
| 2093 | } else { | ||
| 2094 | return nullptr; | ||
| 2095 | } | ||
| 2096 | } | ||
| 2097 | |||
| 2098 | Token *colon_token = &pc->tokens->at(*token_index + 1); | ||
| 2099 | if (colon_token->id != TokenIdColon) { | ||
| 2100 | if (mandatory) { | ||
| 2101 | ast_expect_token(pc, colon_token, TokenIdColon); | ||
| 2102 | } else { | ||
| 2103 | return nullptr; | ||
| 2104 | } | ||
| 2105 | } | ||
| 2106 | |||
| 2107 | *token_index += 2; | ||
| 2108 | |||
| 2109 | AstNode *node = ast_create_node(pc, NodeTypeLabel, symbol_token); | ||
| 2110 | node->data.label.name = token_buf(symbol_token); | ||
| 2111 | return node; | ||
| 2112 | } | ||
| 2113 | |||
| 2114 | static bool statement_terminates_without_semicolon(AstNode *node) { | 2150 | static bool statement_terminates_without_semicolon(AstNode *node) { |
| 2115 | switch (node->type) { | 2151 | switch (node->type) { |
| 2116 | case NodeTypeIfBoolExpr: | 2152 | case NodeTypeIfBoolExpr: |
| ... | @@ -2135,7 +2171,6 @@ static bool statement_terminates_without_semicolon(AstNode *node) { | ... | @@ -2135,7 +2171,6 @@ static bool statement_terminates_without_semicolon(AstNode *node) { |
| 2135 | return node->data.defer.expr->type == NodeTypeBlock; | 2171 | return node->data.defer.expr->type == NodeTypeBlock; |
| 2136 | case NodeTypeSwitchExpr: | 2172 | case NodeTypeSwitchExpr: |
| 2137 | case NodeTypeBlock: | 2173 | case NodeTypeBlock: |
| 2138 | case NodeTypeLabel: | ||
| 2139 | return true; | 2174 | return true; |
| 2140 | default: | 2175 | default: |
| 2141 | return false; | 2176 | return false; |
| ... | @@ -2143,27 +2178,54 @@ static bool statement_terminates_without_semicolon(AstNode *node) { | ... | @@ -2143,27 +2178,54 @@ static bool statement_terminates_without_semicolon(AstNode *node) { |
| 2143 | } | 2178 | } |
| 2144 | 2179 | ||
| 2145 | /* | 2180 | /* |
| 2146 | Block = "{" many(Statement) option(Expression) "}" | 2181 | Block = option(Symbol ":") "{" many(Statement) "}" |
| 2147 | Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | 2182 | Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ExportDecl |
| 2148 | */ | 2183 | */ |
| 2149 | static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) { | 2184 | static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 2185 | size_t orig_token_index = *token_index; | ||
| 2186 | |||
| 2187 | Token *name_token = nullptr; | ||
| 2150 | Token *last_token = &pc->tokens->at(*token_index); | 2188 | Token *last_token = &pc->tokens->at(*token_index); |
| 2151 | 2189 | ||
| 2190 | if (last_token->id == TokenIdSymbol) { | ||
| 2191 | *token_index += 1; | ||
| 2192 | Token *colon_token = &pc->tokens->at(*token_index); | ||
| 2193 | if (colon_token->id == TokenIdColon) { | ||
| 2194 | *token_index += 1; | ||
| 2195 | name_token = last_token; | ||
| 2196 | last_token = &pc->tokens->at(*token_index); | ||
| 2197 | } else if (mandatory) { | ||
| 2198 | ast_expect_token(pc, colon_token, TokenIdColon); | ||
| 2199 | zig_unreachable(); | ||
| 2200 | } else { | ||
| 2201 | *token_index = orig_token_index; | ||
| 2202 | return nullptr; | ||
| 2203 | } | ||
| 2204 | } | ||
| 2205 | |||
| 2152 | if (last_token->id != TokenIdLBrace) { | 2206 | if (last_token->id != TokenIdLBrace) { |
| 2153 | if (mandatory) { | 2207 | if (mandatory) { |
| 2154 | ast_expect_token(pc, last_token, TokenIdLBrace); | 2208 | ast_expect_token(pc, last_token, TokenIdLBrace); |
| 2155 | } else { | 2209 | } else { |
| 2210 | *token_index = orig_token_index; | ||
| 2156 | return nullptr; | 2211 | return nullptr; |
| 2157 | } | 2212 | } |
| 2158 | } | 2213 | } |
| 2159 | *token_index += 1; | 2214 | *token_index += 1; |
| 2160 | 2215 | ||
| 2161 | AstNode *node = ast_create_node(pc, NodeTypeBlock, last_token); | 2216 | AstNode *node = ast_create_node(pc, NodeTypeBlock, last_token); |
| 2217 | if (name_token != nullptr) { | ||
| 2218 | node->data.block.name = token_buf(name_token); | ||
| 2219 | } | ||
| 2162 | 2220 | ||
| 2163 | for (;;) { | 2221 | for (;;) { |
| 2164 | AstNode *statement_node = ast_parse_label(pc, token_index, false); | 2222 | last_token = &pc->tokens->at(*token_index); |
| 2165 | if (!statement_node) | 2223 | if (last_token->id == TokenIdRBrace) { |
| 2166 | statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate); | 2224 | *token_index += 1; |
| 2225 | return node; | ||
| 2226 | } | ||
| 2227 | |||
| 2228 | AstNode *statement_node = ast_parse_local_var_decl(pc, token_index); | ||
| 2167 | if (!statement_node) | 2229 | if (!statement_node) |
| 2168 | statement_node = ast_parse_defer_expr(pc, token_index); | 2230 | statement_node = ast_parse_defer_expr(pc, token_index); |
| 2169 | if (!statement_node) | 2231 | if (!statement_node) |
| ... | @@ -2171,47 +2233,28 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand | ... | @@ -2171,47 +2233,28 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand |
| 2171 | if (!statement_node) | 2233 | if (!statement_node) |
| 2172 | statement_node = ast_parse_expression(pc, token_index, false); | 2234 | statement_node = ast_parse_expression(pc, token_index, false); |
| 2173 | 2235 | ||
| 2174 | bool semicolon_expected = true; | 2236 | if (!statement_node) { |
| 2175 | if (statement_node) { | 2237 | ast_invalid_token_error(pc, last_token); |
| 2176 | node->data.block.statements.append(statement_node); | ||
| 2177 | if (statement_terminates_without_semicolon(statement_node)) { | ||
| 2178 | semicolon_expected = false; | ||
| 2179 | } else { | ||
| 2180 | if (statement_node->type == NodeTypeDefer) { | ||
| 2181 | // defer without a block body requires a semicolon | ||
| 2182 | Token *token = &pc->tokens->at(*token_index); | ||
| 2183 | ast_expect_token(pc, token, TokenIdSemicolon); | ||
| 2184 | } | ||
| 2185 | } | ||
| 2186 | } | 2238 | } |
| 2187 | 2239 | ||
| 2188 | node->data.block.last_statement_is_result_expression = statement_node && !( | 2240 | node->data.block.statements.append(statement_node); |
| 2189 | statement_node->type == NodeTypeLabel || | ||
| 2190 | statement_node->type == NodeTypeDefer); | ||
| 2191 | 2241 | ||
| 2192 | last_token = &pc->tokens->at(*token_index); | 2242 | if (!statement_terminates_without_semicolon(statement_node)) { |
| 2193 | if (last_token->id == TokenIdRBrace) { | 2243 | ast_eat_token(pc, token_index, TokenIdSemicolon); |
| 2194 | *token_index += 1; | ||
| 2195 | return node; | ||
| 2196 | } else if (!semicolon_expected) { | ||
| 2197 | continue; | ||
| 2198 | } else if (last_token->id == TokenIdSemicolon) { | ||
| 2199 | *token_index += 1; | ||
| 2200 | } else { | ||
| 2201 | ast_invalid_token_error(pc, last_token); | ||
| 2202 | } | 2244 | } |
| 2203 | } | 2245 | } |
| 2204 | zig_unreachable(); | 2246 | zig_unreachable(); |
| 2205 | } | 2247 | } |
| 2206 | 2248 | ||
| 2207 | /* | 2249 | /* |
| 2208 | FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("->" TypeExpr) | 2250 | FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("-&gt;" TypeExpr) |
| 2209 | */ | 2251 | */ |
| 2210 | static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { | 2252 | static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { |
| 2211 | Token *first_token = &pc->tokens->at(*token_index); | 2253 | Token *first_token = &pc->tokens->at(*token_index); |
| 2212 | Token *fn_token; | 2254 | Token *fn_token; |
| 2213 | 2255 | ||
| 2214 | CallingConvention cc; | 2256 | CallingConvention cc; |
| 2257 | bool is_extern = false; | ||
| 2215 | if (first_token->id == TokenIdKeywordColdCC) { | 2258 | if (first_token->id == TokenIdKeywordColdCC) { |
| 2216 | *token_index += 1; | 2259 | *token_index += 1; |
| 2217 | fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); | 2260 | fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); |
| ... | @@ -2224,6 +2267,21 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m | ... | @@ -2224,6 +2267,21 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2224 | *token_index += 1; | 2267 | *token_index += 1; |
| 2225 | fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); | 2268 | fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); |
| 2226 | cc = CallingConventionStdcall; | 2269 | cc = CallingConventionStdcall; |
| 2270 | } else if (first_token->id == TokenIdKeywordExtern) { | ||
| 2271 | is_extern = true; | ||
| 2272 | *token_index += 1; | ||
| 2273 | Token *next_token = &pc->tokens->at(*token_index); | ||
| 2274 | if (next_token->id == TokenIdKeywordFn) { | ||
| 2275 | fn_token = next_token; | ||
| 2276 | *token_index += 1; | ||
| 2277 | } else if (mandatory) { | ||
| 2278 | ast_expect_token(pc, next_token, TokenIdKeywordFn); | ||
| 2279 | zig_unreachable(); | ||
| 2280 | } else { | ||
| 2281 | *token_index -= 1; | ||
| 2282 | return nullptr; | ||
| 2283 | } | ||
| 2284 | cc = CallingConventionC; | ||
| 2227 | } else if (first_token->id == TokenIdKeywordFn) { | 2285 | } else if (first_token->id == TokenIdKeywordFn) { |
| 2228 | fn_token = first_token; | 2286 | fn_token = first_token; |
| 2229 | *token_index += 1; | 2287 | *token_index += 1; |
| ... | @@ -2238,6 +2296,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m | ... | @@ -2238,6 +2296,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2238 | AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token); | 2296 | AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token); |
| 2239 | node->data.fn_proto.visib_mod = visib_mod; | 2297 | node->data.fn_proto.visib_mod = visib_mod; |
| 2240 | node->data.fn_proto.cc = cc; | 2298 | node->data.fn_proto.cc = cc; |
| 2299 | node->data.fn_proto.is_extern = is_extern; | ||
| 2241 | 2300 | ||
| 2242 | Token *fn_name = &pc->tokens->at(*token_index); | 2301 | Token *fn_name = &pc->tokens->at(*token_index); |
| 2243 | 2302 | ||
| ... | @@ -2259,6 +2318,14 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m | ... | @@ -2259,6 +2318,14 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2259 | ast_eat_token(pc, token_index, TokenIdRParen); | 2318 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 2260 | next_token = &pc->tokens->at(*token_index); | 2319 | next_token = &pc->tokens->at(*token_index); |
| 2261 | } | 2320 | } |
| 2321 | if (next_token->id == TokenIdKeywordSection) { | ||
| 2322 | *token_index += 1; | ||
| 2323 | ast_eat_token(pc, token_index, TokenIdLParen); | ||
| 2324 | |||
| 2325 | node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true); | ||
| 2326 | ast_eat_token(pc, token_index, TokenIdRParen); | ||
| 2327 | next_token = &pc->tokens->at(*token_index); | ||
| 2328 | } | ||
| 2262 | if (next_token->id == TokenIdArrow) { | 2329 | if (next_token->id == TokenIdArrow) { |
| 2263 | *token_index += 1; | 2330 | *token_index += 1; |
| 2264 | node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, false); | 2331 | node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, false); |
| ... | @@ -2270,35 +2337,35 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m | ... | @@ -2270,35 +2337,35 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2270 | } | 2337 | } |
| 2271 | 2338 | ||
| 2272 | /* | 2339 | /* |
| 2273 | FnDef = option("inline" | "extern") FnProto Block | 2340 | FnDef = option("inline" | "export") FnProto Block |
| 2274 | */ | 2341 | */ |
| 2275 | static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { | 2342 | static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { |
| 2276 | Token *first_token = &pc->tokens->at(*token_index); | 2343 | Token *first_token = &pc->tokens->at(*token_index); |
| 2277 | bool is_inline; | 2344 | bool is_inline; |
| 2278 | bool is_extern; | 2345 | bool is_export; |
| 2279 | if (first_token->id == TokenIdKeywordInline) { | 2346 | if (first_token->id == TokenIdKeywordInline) { |
| 2280 | *token_index += 1; | 2347 | *token_index += 1; |
| 2281 | is_inline = true; | 2348 | is_inline = true; |
| 2282 | is_extern = false; | 2349 | is_export = false; |
| 2283 | } else if (first_token->id == TokenIdKeywordExtern) { | 2350 | } else if (first_token->id == TokenIdKeywordExport) { |
| 2284 | *token_index += 1; | 2351 | *token_index += 1; |
| 2285 | is_extern = true; | 2352 | is_export = true; |
| 2286 | is_inline = false; | 2353 | is_inline = false; |
| 2287 | } else { | 2354 | } else { |
| 2288 | is_inline = false; | 2355 | is_inline = false; |
| 2289 | is_extern = false; | 2356 | is_export = false; |
| 2290 | } | 2357 | } |
| 2291 | 2358 | ||
| 2292 | AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, visib_mod); | 2359 | AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, visib_mod); |
| 2293 | if (!fn_proto) { | 2360 | if (!fn_proto) { |
| 2294 | if (is_inline || is_extern) { | 2361 | if (is_inline || is_export) { |
| 2295 | *token_index -= 1; | 2362 | *token_index -= 1; |
| 2296 | } | 2363 | } |
| 2297 | return nullptr; | 2364 | return nullptr; |
| 2298 | } | 2365 | } |
| 2299 | 2366 | ||
| 2300 | fn_proto->data.fn_proto.is_inline = is_inline; | 2367 | fn_proto->data.fn_proto.is_inline = is_inline; |
| 2301 | fn_proto->data.fn_proto.is_extern = is_extern; | 2368 | fn_proto->data.fn_proto.is_export = is_export; |
| 2302 | 2369 | ||
| 2303 | Token *semi_token = &pc->tokens->at(*token_index); | 2370 | Token *semi_token = &pc->tokens->at(*token_index); |
| 2304 | if (semi_token->id == TokenIdSemicolon) { | 2371 | if (semi_token->id == TokenIdSemicolon) { |
| ... | @@ -2344,7 +2411,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo | ... | @@ -2344,7 +2411,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo |
| 2344 | return fn_proto_node; | 2411 | return fn_proto_node; |
| 2345 | } | 2412 | } |
| 2346 | 2413 | ||
| 2347 | AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); | 2414 | AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod, false, false); |
| 2348 | if (var_decl_node) { | 2415 | if (var_decl_node) { |
| 2349 | ast_eat_token(pc, token_index, TokenIdSemicolon); | 2416 | ast_eat_token(pc, token_index, TokenIdSemicolon); |
| 2350 | 2417 | ||
| ... | @@ -2447,9 +2514,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, | ... | @@ -2447,9 +2514,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, |
| 2447 | if (visib_tok->id == TokenIdKeywordPub) { | 2514 | if (visib_tok->id == TokenIdKeywordPub) { |
| 2448 | *token_index += 1; | 2515 | *token_index += 1; |
| 2449 | visib_mod = VisibModPub; | 2516 | visib_mod = VisibModPub; |
| 2450 | } else if (visib_tok->id == TokenIdKeywordExport) { | ||
| 2451 | *token_index += 1; | ||
| 2452 | visib_mod = VisibModExport; | ||
| 2453 | } else { | 2517 | } else { |
| 2454 | visib_mod = VisibModPrivate; | 2518 | visib_mod = VisibModPrivate; |
| 2455 | } | 2519 | } |
| ... | @@ -2460,7 +2524,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, | ... | @@ -2460,7 +2524,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, |
| 2460 | continue; | 2524 | continue; |
| 2461 | } | 2525 | } |
| 2462 | 2526 | ||
| 2463 | AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); | 2527 | AstNode *var_decl_node = ast_parse_global_var_decl(pc, token_index, visib_mod); |
| 2464 | if (var_decl_node) { | 2528 | if (var_decl_node) { |
| 2465 | ast_eat_token(pc, token_index, TokenIdSemicolon); | 2529 | ast_eat_token(pc, token_index, TokenIdSemicolon); |
| 2466 | node->data.container_decl.decls.append(var_decl_node); | 2530 | node->data.container_decl.decls.append(var_decl_node); |
| ... | @@ -2553,7 +2617,7 @@ static AstNode *ast_parse_test_decl_node(ParseContext *pc, size_t *token_index) | ... | @@ -2553,7 +2617,7 @@ static AstNode *ast_parse_test_decl_node(ParseContext *pc, size_t *token_index) |
| 2553 | 2617 | ||
| 2554 | /* | 2618 | /* |
| 2555 | TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl | 2619 | TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl |
| 2556 | TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl) | 2620 | TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) |
| 2557 | */ | 2621 | */ |
| 2558 | static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList<AstNode *> *top_level_decls) { | 2622 | static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList<AstNode *> *top_level_decls) { |
| 2559 | for (;;) { | 2623 | for (;;) { |
| ... | @@ -2580,9 +2644,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig | ... | @@ -2580,9 +2644,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig |
| 2580 | if (visib_tok->id == TokenIdKeywordPub) { | 2644 | if (visib_tok->id == TokenIdKeywordPub) { |
| 2581 | *token_index += 1; | 2645 | *token_index += 1; |
| 2582 | visib_mod = VisibModPub; | 2646 | visib_mod = VisibModPub; |
| 2583 | } else if (visib_tok->id == TokenIdKeywordExport) { | ||
| 2584 | *token_index += 1; | ||
| 2585 | visib_mod = VisibModExport; | ||
| 2586 | } else { | 2647 | } else { |
| 2587 | visib_mod = VisibModPrivate; | 2648 | visib_mod = VisibModPrivate; |
| 2588 | } | 2649 | } |
| ... | @@ -2605,7 +2666,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig | ... | @@ -2605,7 +2666,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig |
| 2605 | continue; | 2666 | continue; |
| 2606 | } | 2667 | } |
| 2607 | 2668 | ||
| 2608 | AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); | 2669 | AstNode *var_decl_node = ast_parse_global_var_decl(pc, token_index, visib_mod); |
| 2609 | if (var_decl_node) { | 2670 | if (var_decl_node) { |
| 2610 | ast_eat_token(pc, token_index, TokenIdSemicolon); | 2671 | ast_eat_token(pc, token_index, TokenIdSemicolon); |
| 2611 | top_level_decls->append(var_decl_node); | 2672 | top_level_decls->append(var_decl_node); |
| ... | @@ -2669,6 +2730,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -2669,6 +2730,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2669 | visit_field(&node->data.fn_proto.return_type, visit, context); | 2730 | visit_field(&node->data.fn_proto.return_type, visit, context); |
| 2670 | visit_node_list(&node->data.fn_proto.params, visit, context); | 2731 | visit_node_list(&node->data.fn_proto.params, visit, context); |
| 2671 | visit_field(&node->data.fn_proto.align_expr, visit, context); | 2732 | visit_field(&node->data.fn_proto.align_expr, visit, context); |
| 2733 | visit_field(&node->data.fn_proto.section_expr, visit, context); | ||
| 2672 | break; | 2734 | break; |
| 2673 | case NodeTypeFnDef: | 2735 | case NodeTypeFnDef: |
| 2674 | visit_field(&node->data.fn_def.fn_proto, visit, context); | 2736 | visit_field(&node->data.fn_def.fn_proto, visit, context); |
| ... | @@ -2696,6 +2758,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -2696,6 +2758,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2696 | visit_field(&node->data.variable_declaration.type, visit, context); | 2758 | visit_field(&node->data.variable_declaration.type, visit, context); |
| 2697 | visit_field(&node->data.variable_declaration.expr, visit, context); | 2759 | visit_field(&node->data.variable_declaration.expr, visit, context); |
| 2698 | visit_field(&node->data.variable_declaration.align_expr, visit, context); | 2760 | visit_field(&node->data.variable_declaration.align_expr, visit, context); |
| 2761 | visit_field(&node->data.variable_declaration.section_expr, visit, context); | ||
| 2699 | break; | 2762 | break; |
| 2700 | case NodeTypeErrorValueDecl: | 2763 | case NodeTypeErrorValueDecl: |
| 2701 | // none | 2764 | // none |
| ... | @@ -2799,12 +2862,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -2799,12 +2862,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2799 | visit_field(&node->data.switch_range.start, visit, context); | 2862 | visit_field(&node->data.switch_range.start, visit, context); |
| 2800 | visit_field(&node->data.switch_range.end, visit, context); | 2863 | visit_field(&node->data.switch_range.end, visit, context); |
| 2801 | break; | 2864 | break; |
| 2802 | case NodeTypeLabel: | ||
| 2803 | // none | ||
| 2804 | break; | ||
| 2805 | case NodeTypeGoto: | ||
| 2806 | // none | ||
| 2807 | break; | ||
| 2808 | case NodeTypeCompTime: | 2865 | case NodeTypeCompTime: |
| 2809 | visit_field(&node->data.comptime_expr.expr, visit, context); | 2866 | visit_field(&node->data.comptime_expr.expr, visit, context); |
| 2810 | break; | 2867 | break; |
src/tokenizer.cpp+2| ... | @@ -134,6 +134,7 @@ static const struct ZigKeyword zig_keywords[] = { | ... | @@ -134,6 +134,7 @@ static const struct ZigKeyword zig_keywords[] = { |
| 134 | {"packed", TokenIdKeywordPacked}, | 134 | {"packed", TokenIdKeywordPacked}, |
| 135 | {"pub", TokenIdKeywordPub}, | 135 | {"pub", TokenIdKeywordPub}, |
| 136 | {"return", TokenIdKeywordReturn}, | 136 | {"return", TokenIdKeywordReturn}, |
| 137 | {"section", TokenIdKeywordSection}, | ||
| 137 | {"stdcallcc", TokenIdKeywordStdcallCC}, | 138 | {"stdcallcc", TokenIdKeywordStdcallCC}, |
| 138 | {"struct", TokenIdKeywordStruct}, | 139 | {"struct", TokenIdKeywordStruct}, |
| 139 | {"switch", TokenIdKeywordSwitch}, | 140 | {"switch", TokenIdKeywordSwitch}, |
| ... | @@ -1533,6 +1534,7 @@ const char * token_name(TokenId id) { | ... | @@ -1533,6 +1534,7 @@ const char * token_name(TokenId id) { |
| 1533 | case TokenIdKeywordPacked: return "packed"; | 1534 | case TokenIdKeywordPacked: return "packed"; |
| 1534 | case TokenIdKeywordPub: return "pub"; | 1535 | case TokenIdKeywordPub: return "pub"; |
| 1535 | case TokenIdKeywordReturn: return "return"; | 1536 | case TokenIdKeywordReturn: return "return"; |
| 1537 | case TokenIdKeywordSection: return "section"; | ||
| 1536 | case TokenIdKeywordStdcallCC: return "stdcallcc"; | 1538 | case TokenIdKeywordStdcallCC: return "stdcallcc"; |
| 1537 | case TokenIdKeywordStruct: return "struct"; | 1539 | case TokenIdKeywordStruct: return "struct"; |
| 1538 | case TokenIdKeywordSwitch: return "switch"; | 1540 | case TokenIdKeywordSwitch: return "switch"; |
src/tokenizer.hpp+1| ... | @@ -47,6 +47,7 @@ enum TokenId { | ... | @@ -47,6 +47,7 @@ enum TokenId { |
| 47 | TokenIdFloatLiteral, | 47 | TokenIdFloatLiteral, |
| 48 | TokenIdIntLiteral, | 48 | TokenIdIntLiteral, |
| 49 | TokenIdKeywordAlign, | 49 | TokenIdKeywordAlign, |
| 50 | TokenIdKeywordSection, | ||
| 50 | TokenIdKeywordAnd, | 51 | TokenIdKeywordAnd, |
| 51 | TokenIdKeywordAsm, | 52 | TokenIdKeywordAsm, |
| 52 | TokenIdKeywordBreak, | 53 | TokenIdKeywordBreak, |
src/translate_c.cpp+185-244| ... | @@ -73,7 +73,7 @@ struct Context { | ... | @@ -73,7 +73,7 @@ struct Context { |
| 73 | ImportTableEntry *import; | 73 | ImportTableEntry *import; |
| 74 | ZigList<ErrorMsg *> *errors; | 74 | ZigList<ErrorMsg *> *errors; |
| 75 | VisibMod visib_mod; | 75 | VisibMod visib_mod; |
| 76 | VisibMod export_visib_mod; | 76 | bool want_export; |
| 77 | AstNode *root; | 77 | AstNode *root; |
| 78 | HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table; | 78 | HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table; |
| 79 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table; | 79 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table; |
| ... | @@ -104,10 +104,8 @@ static TransScopeRoot *trans_scope_root_create(Context *c); | ... | @@ -104,10 +104,8 @@ static TransScopeRoot *trans_scope_root_create(Context *c); |
| 104 | static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope); | 104 | static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope); |
| 105 | static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope); | 105 | static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope); |
| 106 | static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name); | 106 | static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name); |
| 107 | static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope); | ||
| 108 | 107 | ||
| 109 | static TransScopeBlock *trans_scope_block_find(TransScope *scope); | 108 | static TransScopeBlock *trans_scope_block_find(TransScope *scope); |
| 110 | static TransScopeSwitch *trans_scope_switch_find(TransScope *scope); | ||
| 111 | 109 | ||
| 112 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); | 110 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); |
| 113 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); | 111 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); |
| ... | @@ -173,6 +171,28 @@ static AstNode * trans_create_node(Context *c, NodeType id) { | ... | @@ -173,6 +171,28 @@ static AstNode * trans_create_node(Context *c, NodeType id) { |
| 173 | return node; | 171 | return node; |
| 174 | } | 172 | } |
| 175 | 173 | ||
| 174 | static AstNode *trans_create_node_break(Context *c, Buf *label_name, AstNode *value_node) { | ||
| 175 | AstNode *node = trans_create_node(c, NodeTypeBreak); | ||
| 176 | node->data.break_expr.name = label_name; | ||
| 177 | node->data.break_expr.expr = value_node; | ||
| 178 | return node; | ||
| 179 | } | ||
| 180 | |||
| 181 | static AstNode *trans_create_node_return(Context *c, AstNode *value_node) { | ||
| 182 | AstNode *node = trans_create_node(c, NodeTypeReturnExpr); | ||
| 183 | node->data.return_expr.kind = ReturnKindUnconditional; | ||
| 184 | node->data.return_expr.expr = value_node; | ||
| 185 | return node; | ||
| 186 | } | ||
| 187 | |||
| 188 | static AstNode *trans_create_node_if(Context *c, AstNode *cond_node, AstNode *then_node, AstNode *else_node) { | ||
| 189 | AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); | ||
| 190 | node->data.if_bool_expr.condition = cond_node; | ||
| 191 | node->data.if_bool_expr.then_block = then_node; | ||
| 192 | node->data.if_bool_expr.else_node = else_node; | ||
| 193 | return node; | ||
| 194 | } | ||
| 195 | |||
| 176 | static AstNode *trans_create_node_float_lit(Context *c, double value) { | 196 | static AstNode *trans_create_node_float_lit(Context *c, double value) { |
| 177 | AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); | 197 | AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); |
| 178 | node->data.float_literal.bigfloat = allocate<BigFloat>(1); | 198 | node->data.float_literal.bigfloat = allocate<BigFloat>(1); |
| ... | @@ -257,18 +277,6 @@ static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_vol | ... | @@ -257,18 +277,6 @@ static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_vol |
| 257 | return node; | 277 | return node; |
| 258 | } | 278 | } |
| 259 | 279 | ||
| 260 | static AstNode *trans_create_node_goto(Context *c, Buf *label_name) { | ||
| 261 | AstNode *goto_node = trans_create_node(c, NodeTypeGoto); | ||
| 262 | goto_node->data.goto_expr.name = label_name; | ||
| 263 | return goto_node; | ||
| 264 | } | ||
| 265 | |||
| 266 | static AstNode *trans_create_node_label(Context *c, Buf *label_name) { | ||
| 267 | AstNode *label_node = trans_create_node(c, NodeTypeLabel); | ||
| 268 | label_node->data.label.name = label_name; | ||
| 269 | return label_node; | ||
| 270 | } | ||
| 271 | |||
| 272 | static AstNode *trans_create_node_bool(Context *c, bool value) { | 280 | static AstNode *trans_create_node_bool(Context *c, bool value) { |
| 273 | AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral); | 281 | AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral); |
| 274 | bool_node->data.bool_literal.value = value; | 282 | bool_node->data.bool_literal.value = value; |
| ... | @@ -378,8 +386,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r | ... | @@ -378,8 +386,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r |
| 378 | 386 | ||
| 379 | AstNode *block = trans_create_node(c, NodeTypeBlock); | 387 | AstNode *block = trans_create_node(c, NodeTypeBlock); |
| 380 | block->data.block.statements.resize(1); | 388 | block->data.block.statements.resize(1); |
| 381 | block->data.block.statements.items[0] = fn_call_node; | 389 | block->data.block.statements.items[0] = trans_create_node_return(c, fn_call_node); |
| 382 | block->data.block.last_statement_is_result_expression = true; | ||
| 383 | 390 | ||
| 384 | fn_def->data.fn_def.body = block; | 391 | fn_def->data.fn_def.body = block; |
| 385 | return fn_def; | 392 | return fn_def; |
| ... | @@ -1149,13 +1156,15 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco | ... | @@ -1149,13 +1156,15 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco |
| 1149 | } else { | 1156 | } else { |
| 1150 | // worst case | 1157 | // worst case |
| 1151 | // c: lhs = rhs | 1158 | // c: lhs = rhs |
| 1152 | // zig: { | 1159 | // zig: x: { |
| 1153 | // zig: const _tmp = rhs; | 1160 | // zig: const _tmp = rhs; |
| 1154 | // zig: lhs = _tmp; | 1161 | // zig: lhs = _tmp; |
| 1155 | // zig: _tmp | 1162 | // zig: break :x _tmp |
| 1156 | // zig: } | 1163 | // zig: } |
| 1157 | 1164 | ||
| 1158 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | 1165 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); |
| 1166 | Buf *label_name = buf_create_from_str("x"); | ||
| 1167 | child_scope->node->data.block.name = label_name; | ||
| 1159 | 1168 | ||
| 1160 | // const _tmp = rhs; | 1169 | // const _tmp = rhs; |
| 1161 | AstNode *rhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, rhs, TransRValue); | 1170 | AstNode *rhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, rhs, TransRValue); |
| ... | @@ -1172,9 +1181,9 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco | ... | @@ -1172,9 +1181,9 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco |
| 1172 | trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign, | 1181 | trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign, |
| 1173 | trans_create_node_symbol(c, tmp_var_name))); | 1182 | trans_create_node_symbol(c, tmp_var_name))); |
| 1174 | 1183 | ||
| 1175 | // _tmp | 1184 | // break :x _tmp |
| 1176 | child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | 1185 | AstNode *tmp_symbol_node = trans_create_node_symbol(c, tmp_var_name); |
| 1177 | child_scope->node->data.block.last_statement_is_result_expression = true; | 1186 | child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, tmp_symbol_node)); |
| 1178 | 1187 | ||
| 1179 | return child_scope->node; | 1188 | return child_scope->node; |
| 1180 | } | 1189 | } |
| ... | @@ -1279,6 +1288,9 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS | ... | @@ -1279,6 +1288,9 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS |
| 1279 | case BO_Comma: | 1288 | case BO_Comma: |
| 1280 | { | 1289 | { |
| 1281 | TransScopeBlock *scope_block = trans_scope_block_create(c, scope); | 1290 | TransScopeBlock *scope_block = trans_scope_block_create(c, scope); |
| 1291 | Buf *label_name = buf_create_from_str("x"); | ||
| 1292 | scope_block->node->data.block.name = label_name; | ||
| 1293 | |||
| 1282 | AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue); | 1294 | AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue); |
| 1283 | if (lhs == nullptr) | 1295 | if (lhs == nullptr) |
| 1284 | return nullptr; | 1296 | return nullptr; |
| ... | @@ -1287,9 +1299,7 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS | ... | @@ -1287,9 +1299,7 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS |
| 1287 | AstNode *rhs = trans_expr(c, result_used, &scope_block->base, stmt->getRHS(), TransRValue); | 1299 | AstNode *rhs = trans_expr(c, result_used, &scope_block->base, stmt->getRHS(), TransRValue); |
| 1288 | if (rhs == nullptr) | 1300 | if (rhs == nullptr) |
| 1289 | return nullptr; | 1301 | return nullptr; |
| 1290 | scope_block->node->data.block.statements.append(maybe_suppress_result(c, result_used, rhs)); | 1302 | scope_block->node->data.block.statements.append(trans_create_node_break(c, label_name, maybe_suppress_result(c, result_used, rhs))); |
| 1291 | |||
| 1292 | scope_block->node->data.block.last_statement_is_result_expression = true; | ||
| 1293 | return scope_block->node; | 1303 | return scope_block->node; |
| 1294 | } | 1304 | } |
| 1295 | case BO_MulAssign: | 1305 | case BO_MulAssign: |
| ... | @@ -1329,14 +1339,16 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result | ... | @@ -1329,14 +1339,16 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result |
| 1329 | } else { | 1339 | } else { |
| 1330 | // need more complexity. worst case, this looks like this: | 1340 | // need more complexity. worst case, this looks like this: |
| 1331 | // c: lhs >>= rhs | 1341 | // c: lhs >>= rhs |
| 1332 | // zig: { | 1342 | // zig: x: { |
| 1333 | // zig: const _ref = &lhs; | 1343 | // zig: const _ref = &lhs; |
| 1334 | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | 1344 | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); |
| 1335 | // zig: *_ref | 1345 | // zig: break :x *_ref |
| 1336 | // zig: } | 1346 | // zig: } |
| 1337 | // where u5 is the appropriate type | 1347 | // where u5 is the appropriate type |
| 1338 | 1348 | ||
| 1339 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | 1349 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); |
| 1350 | Buf *label_name = buf_create_from_str("x"); | ||
| 1351 | child_scope->node->data.block.name = label_name; | ||
| 1340 | 1352 | ||
| 1341 | // const _ref = &lhs; | 1353 | // const _ref = &lhs; |
| 1342 | AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue); | 1354 | AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue); |
| ... | @@ -1378,11 +1390,11 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result | ... | @@ -1378,11 +1390,11 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result |
| 1378 | child_scope->node->data.block.statements.append(assign_statement); | 1390 | child_scope->node->data.block.statements.append(assign_statement); |
| 1379 | 1391 | ||
| 1380 | if (result_used == ResultUsedYes) { | 1392 | if (result_used == ResultUsedYes) { |
| 1381 | // *_ref | 1393 | // break :x *_ref |
| 1382 | child_scope->node->data.block.statements.append( | 1394 | child_scope->node->data.block.statements.append( |
| 1383 | trans_create_node_prefix_op(c, PrefixOpDereference, | 1395 | trans_create_node_break(c, label_name, |
| 1384 | trans_create_node_symbol(c, tmp_var_name))); | 1396 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1385 | child_scope->node->data.block.last_statement_is_result_expression = true; | 1397 | trans_create_node_symbol(c, tmp_var_name)))); |
| 1386 | } | 1398 | } |
| 1387 | 1399 | ||
| 1388 | return child_scope->node; | 1400 | return child_scope->node; |
| ... | @@ -1403,13 +1415,15 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, | ... | @@ -1403,13 +1415,15 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, |
| 1403 | } else { | 1415 | } else { |
| 1404 | // need more complexity. worst case, this looks like this: | 1416 | // need more complexity. worst case, this looks like this: |
| 1405 | // c: lhs += rhs | 1417 | // c: lhs += rhs |
| 1406 | // zig: { | 1418 | // zig: x: { |
| 1407 | // zig: const _ref = &lhs; | 1419 | // zig: const _ref = &lhs; |
| 1408 | // zig: *_ref = *_ref + rhs; | 1420 | // zig: *_ref = *_ref + rhs; |
| 1409 | // zig: *_ref | 1421 | // zig: break :x *_ref |
| 1410 | // zig: } | 1422 | // zig: } |
| 1411 | 1423 | ||
| 1412 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | 1424 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); |
| 1425 | Buf *label_name = buf_create_from_str("x"); | ||
| 1426 | child_scope->node->data.block.name = label_name; | ||
| 1413 | 1427 | ||
| 1414 | // const _ref = &lhs; | 1428 | // const _ref = &lhs; |
| 1415 | AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue); | 1429 | AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue); |
| ... | @@ -1436,11 +1450,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, | ... | @@ -1436,11 +1450,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, |
| 1436 | rhs)); | 1450 | rhs)); |
| 1437 | child_scope->node->data.block.statements.append(assign_statement); | 1451 | child_scope->node->data.block.statements.append(assign_statement); |
| 1438 | 1452 | ||
| 1439 | // *_ref | 1453 | // break :x *_ref |
| 1440 | child_scope->node->data.block.statements.append( | 1454 | child_scope->node->data.block.statements.append( |
| 1441 | trans_create_node_prefix_op(c, PrefixOpDereference, | 1455 | trans_create_node_break(c, label_name, |
| 1442 | trans_create_node_symbol(c, tmp_var_name))); | 1456 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1443 | child_scope->node->data.block.last_statement_is_result_expression = true; | 1457 | trans_create_node_symbol(c, tmp_var_name)))); |
| 1444 | 1458 | ||
| 1445 | return child_scope->node; | 1459 | return child_scope->node; |
| 1446 | } | 1460 | } |
| ... | @@ -1735,13 +1749,15 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr | ... | @@ -1735,13 +1749,15 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr |
| 1735 | } | 1749 | } |
| 1736 | // worst case | 1750 | // worst case |
| 1737 | // c: expr++ | 1751 | // c: expr++ |
| 1738 | // zig: { | 1752 | // zig: x: { |
| 1739 | // zig: const _ref = &expr; | 1753 | // zig: const _ref = &expr; |
| 1740 | // zig: const _tmp = *_ref; | 1754 | // zig: const _tmp = *_ref; |
| 1741 | // zig: *_ref += 1; | 1755 | // zig: *_ref += 1; |
| 1742 | // zig: _tmp | 1756 | // zig: break :x _tmp |
| 1743 | // zig: } | 1757 | // zig: } |
| 1744 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | 1758 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); |
| 1759 | Buf *label_name = buf_create_from_str("x"); | ||
| 1760 | child_scope->node->data.block.name = label_name; | ||
| 1745 | 1761 | ||
| 1746 | // const _ref = &expr; | 1762 | // const _ref = &expr; |
| 1747 | AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue); | 1763 | AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue); |
| ... | @@ -1767,9 +1783,8 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr | ... | @@ -1767,9 +1783,8 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr |
| 1767 | trans_create_node_unsigned(c, 1)); | 1783 | trans_create_node_unsigned(c, 1)); |
| 1768 | child_scope->node->data.block.statements.append(assign_statement); | 1784 | child_scope->node->data.block.statements.append(assign_statement); |
| 1769 | 1785 | ||
| 1770 | // _tmp | 1786 | // break :x _tmp |
| 1771 | child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | 1787 | child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, trans_create_node_symbol(c, tmp_var_name))); |
| 1772 | child_scope->node->data.block.last_statement_is_result_expression = true; | ||
| 1773 | 1788 | ||
| 1774 | return child_scope->node; | 1789 | return child_scope->node; |
| 1775 | } | 1790 | } |
| ... | @@ -1790,12 +1805,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra | ... | @@ -1790,12 +1805,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra |
| 1790 | } | 1805 | } |
| 1791 | // worst case | 1806 | // worst case |
| 1792 | // c: ++expr | 1807 | // c: ++expr |
| 1793 | // zig: { | 1808 | // zig: x: { |
| 1794 | // zig: const _ref = &expr; | 1809 | // zig: const _ref = &expr; |
| 1795 | // zig: *_ref += 1; | 1810 | // zig: *_ref += 1; |
| 1796 | // zig: *_ref | 1811 | // zig: break :x *_ref |
| 1797 | // zig: } | 1812 | // zig: } |
| 1798 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | 1813 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); |
| 1814 | Buf *label_name = buf_create_from_str("x"); | ||
| 1815 | child_scope->node->data.block.name = label_name; | ||
| 1799 | 1816 | ||
| 1800 | // const _ref = &expr; | 1817 | // const _ref = &expr; |
| 1801 | AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue); | 1818 | AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue); |
| ... | @@ -1814,11 +1831,10 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra | ... | @@ -1814,11 +1831,10 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra |
| 1814 | trans_create_node_unsigned(c, 1)); | 1831 | trans_create_node_unsigned(c, 1)); |
| 1815 | child_scope->node->data.block.statements.append(assign_statement); | 1832 | child_scope->node->data.block.statements.append(assign_statement); |
| 1816 | 1833 | ||
| 1817 | // *_ref | 1834 | // break :x *_ref |
| 1818 | AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference, | 1835 | AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1819 | trans_create_node_symbol(c, ref_var_name)); | 1836 | trans_create_node_symbol(c, ref_var_name)); |
| 1820 | child_scope->node->data.block.statements.append(deref_expr); | 1837 | child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr)); |
| 1821 | child_scope->node->data.block.last_statement_is_result_expression = true; | ||
| 1822 | 1838 | ||
| 1823 | return child_scope->node; | 1839 | return child_scope->node; |
| 1824 | } | 1840 | } |
| ... | @@ -2374,145 +2390,6 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt | ... | @@ -2374,145 +2390,6 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt |
| 2374 | return while_scope->node; | 2390 | return while_scope->node; |
| 2375 | } | 2391 | } |
| 2376 | 2392 | ||
| 2377 | static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) { | ||
| 2378 | TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope); | ||
| 2379 | |||
| 2380 | TransScopeSwitch *switch_scope; | ||
| 2381 | |||
| 2382 | const DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt(); | ||
| 2383 | if (var_decl_stmt == nullptr) { | ||
| 2384 | switch_scope = trans_scope_switch_create(c, &block_scope->base); | ||
| 2385 | } else { | ||
| 2386 | AstNode *vars_node; | ||
| 2387 | TransScope *var_scope = trans_stmt(c, &block_scope->base, var_decl_stmt, &vars_node); | ||
| 2388 | if (var_scope == nullptr) | ||
| 2389 | return nullptr; | ||
| 2390 | if (vars_node != nullptr) | ||
| 2391 | block_scope->node->data.block.statements.append(vars_node); | ||
| 2392 | switch_scope = trans_scope_switch_create(c, var_scope); | ||
| 2393 | } | ||
| 2394 | block_scope->node->data.block.statements.append(switch_scope->switch_node); | ||
| 2395 | |||
| 2396 | // TODO avoid name collisions | ||
| 2397 | Buf *end_label_name = buf_create_from_str("end"); | ||
| 2398 | switch_scope->end_label_name = end_label_name; | ||
| 2399 | |||
| 2400 | const Expr *cond_expr = stmt->getCond(); | ||
| 2401 | assert(cond_expr != nullptr); | ||
| 2402 | |||
| 2403 | AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue); | ||
| 2404 | if (expr_node == nullptr) | ||
| 2405 | return nullptr; | ||
| 2406 | switch_scope->switch_node->data.switch_expr.expr = expr_node; | ||
| 2407 | |||
| 2408 | AstNode *body_node; | ||
| 2409 | const Stmt *body_stmt = stmt->getBody(); | ||
| 2410 | if (body_stmt->getStmtClass() == Stmt::CompoundStmtClass) { | ||
| 2411 | if (trans_compound_stmt_inline(c, &switch_scope->base, (const CompoundStmt *)body_stmt, | ||
| 2412 | block_scope->node, nullptr)) | ||
| 2413 | { | ||
| 2414 | return nullptr; | ||
| 2415 | } | ||
| 2416 | } else { | ||
| 2417 | TransScope *body_scope = trans_stmt(c, &switch_scope->base, body_stmt, &body_node); | ||
| 2418 | if (body_scope == nullptr) | ||
| 2419 | return nullptr; | ||
| 2420 | if (body_node != nullptr) | ||
| 2421 | block_scope->node->data.block.statements.append(body_node); | ||
| 2422 | } | ||
| 2423 | |||
| 2424 | if (!switch_scope->found_default && !stmt->isAllEnumCasesCovered()) { | ||
| 2425 | AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); | ||
| 2426 | prong_node->data.switch_prong.expr = trans_create_node_goto(c, end_label_name); | ||
| 2427 | switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); | ||
| 2428 | } | ||
| 2429 | |||
| 2430 | // This is necessary if the last switch case "falls through" the end of the switch block | ||
| 2431 | block_scope->node->data.block.statements.append(trans_create_node_goto(c, end_label_name)); | ||
| 2432 | |||
| 2433 | block_scope->node->data.block.statements.append(trans_create_node_label(c, end_label_name)); | ||
| 2434 | |||
| 2435 | return block_scope->node; | ||
| 2436 | } | ||
| 2437 | |||
| 2438 | static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node, | ||
| 2439 | TransScope **out_scope) | ||
| 2440 | { | ||
| 2441 | *out_node = nullptr; | ||
| 2442 | |||
| 2443 | if (stmt->getRHS() != nullptr) { | ||
| 2444 | emit_warning(c, stmt->getLocStart(), "TODO support GNU switch case a ... b extension"); | ||
| 2445 | return ErrorUnexpected; | ||
| 2446 | } | ||
| 2447 | |||
| 2448 | TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope); | ||
| 2449 | assert(switch_scope != nullptr); | ||
| 2450 | |||
| 2451 | Buf *label_name = buf_sprintf("case_%" PRIu32, switch_scope->case_index); | ||
| 2452 | switch_scope->case_index += 1; | ||
| 2453 | |||
| 2454 | { | ||
| 2455 | // Add the prong | ||
| 2456 | AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); | ||
| 2457 | AstNode *item_node = trans_expr(c, ResultUsedYes, &switch_scope->base, stmt->getLHS(), TransRValue); | ||
| 2458 | if (item_node == nullptr) | ||
| 2459 | return ErrorUnexpected; | ||
| 2460 | prong_node->data.switch_prong.items.append(item_node); | ||
| 2461 | |||
| 2462 | prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name); | ||
| 2463 | |||
| 2464 | switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); | ||
| 2465 | } | ||
| 2466 | |||
| 2467 | TransScopeBlock *scope_block = trans_scope_block_find(parent_scope); | ||
| 2468 | scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name)); | ||
| 2469 | |||
| 2470 | AstNode *sub_stmt_node; | ||
| 2471 | TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node); | ||
| 2472 | if (new_scope == nullptr) | ||
| 2473 | return ErrorUnexpected; | ||
| 2474 | if (sub_stmt_node != nullptr) | ||
| 2475 | scope_block->node->data.block.statements.append(sub_stmt_node); | ||
| 2476 | |||
| 2477 | *out_scope = new_scope; | ||
| 2478 | return ErrorNone; | ||
| 2479 | } | ||
| 2480 | |||
| 2481 | static int trans_switch_default(Context *c, TransScope *parent_scope, const DefaultStmt *stmt, AstNode **out_node, | ||
| 2482 | TransScope **out_scope) | ||
| 2483 | { | ||
| 2484 | *out_node = nullptr; | ||
| 2485 | |||
| 2486 | TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope); | ||
| 2487 | assert(switch_scope != nullptr); | ||
| 2488 | |||
| 2489 | Buf *label_name = buf_sprintf("default"); | ||
| 2490 | |||
| 2491 | { | ||
| 2492 | // Add the prong | ||
| 2493 | AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); | ||
| 2494 | |||
| 2495 | prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name); | ||
| 2496 | |||
| 2497 | switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); | ||
| 2498 | switch_scope->found_default = true; | ||
| 2499 | } | ||
| 2500 | |||
| 2501 | TransScopeBlock *scope_block = trans_scope_block_find(parent_scope); | ||
| 2502 | scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name)); | ||
| 2503 | |||
| 2504 | |||
| 2505 | AstNode *sub_stmt_node; | ||
| 2506 | TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node); | ||
| 2507 | if (new_scope == nullptr) | ||
| 2508 | return ErrorUnexpected; | ||
| 2509 | if (sub_stmt_node != nullptr) | ||
| 2510 | scope_block->node->data.block.statements.append(sub_stmt_node); | ||
| 2511 | |||
| 2512 | *out_scope = new_scope; | ||
| 2513 | return ErrorNone; | ||
| 2514 | } | ||
| 2515 | |||
| 2516 | static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForStmt *stmt) { | 2393 | static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForStmt *stmt) { |
| 2517 | AstNode *loop_block_node; | 2394 | AstNode *loop_block_node; |
| 2518 | TransScopeWhile *while_scope; | 2395 | TransScopeWhile *while_scope; |
| ... | @@ -2590,8 +2467,7 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt | ... | @@ -2590,8 +2467,7 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt |
| 2590 | if (cur_scope->id == TransScopeIdWhile) { | 2467 | if (cur_scope->id == TransScopeIdWhile) { |
| 2591 | return trans_create_node(c, NodeTypeBreak); | 2468 | return trans_create_node(c, NodeTypeBreak); |
| 2592 | } else if (cur_scope->id == TransScopeIdSwitch) { | 2469 | } else if (cur_scope->id == TransScopeIdSwitch) { |
| 2593 | TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope; | 2470 | zig_panic("TODO"); |
| 2594 | return trans_create_node_goto(c, switch_scope->end_label_name); | ||
| 2595 | } | 2471 | } |
| 2596 | cur_scope = cur_scope->parent; | 2472 | cur_scope = cur_scope->parent; |
| 2597 | } | 2473 | } |
| ... | @@ -2691,12 +2567,14 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, | ... | @@ -2691,12 +2567,14 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, |
| 2691 | return wrap_stmt(out_node, out_child_scope, scope, | 2567 | return wrap_stmt(out_node, out_child_scope, scope, |
| 2692 | trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue)); | 2568 | trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue)); |
| 2693 | case Stmt::SwitchStmtClass: | 2569 | case Stmt::SwitchStmtClass: |
| 2694 | return wrap_stmt(out_node, out_child_scope, scope, | 2570 | emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass"); |
| 2695 | trans_switch_stmt(c, scope, (const SwitchStmt *)stmt)); | 2571 | return ErrorUnexpected; |
| 2696 | case Stmt::CaseStmtClass: | 2572 | case Stmt::CaseStmtClass: |
| 2697 | return trans_switch_case(c, scope, (const CaseStmt *)stmt, out_node, out_child_scope); | 2573 | emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); |
| 2574 | return ErrorUnexpected; | ||
| 2698 | case Stmt::DefaultStmtClass: | 2575 | case Stmt::DefaultStmtClass: |
| 2699 | return trans_switch_default(c, scope, (const DefaultStmt *)stmt, out_node, out_child_scope); | 2576 | emit_warning(c, stmt->getLocStart(), "TODO handle C DefaultStmtClass"); |
| 2577 | return ErrorUnexpected; | ||
| 2700 | case Stmt::NoStmtClass: | 2578 | case Stmt::NoStmtClass: |
| 2701 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass"); | 2579 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass"); |
| 2702 | return ErrorUnexpected; | 2580 | return ErrorUnexpected; |
| ... | @@ -3246,7 +3124,8 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { | ... | @@ -3246,7 +3124,8 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { |
| 3246 | 3124 | ||
| 3247 | StorageClass sc = fn_decl->getStorageClass(); | 3125 | StorageClass sc = fn_decl->getStorageClass(); |
| 3248 | if (sc == SC_None) { | 3126 | if (sc == SC_None) { |
| 3249 | proto_node->data.fn_proto.visib_mod = fn_decl->hasBody() ? c->export_visib_mod : c->visib_mod; | 3127 | proto_node->data.fn_proto.visib_mod = c->visib_mod; |
| 3128 | proto_node->data.fn_proto.is_export = fn_decl->hasBody() ? c->want_export : false; | ||
| 3250 | } else if (sc == SC_Extern || sc == SC_Static) { | 3129 | } else if (sc == SC_Extern || sc == SC_Static) { |
| 3251 | proto_node->data.fn_proto.visib_mod = c->visib_mod; | 3130 | proto_node->data.fn_proto.visib_mod = c->visib_mod; |
| 3252 | } else if (sc == SC_PrivateExtern) { | 3131 | } else if (sc == SC_PrivateExtern) { |
| ... | @@ -3865,14 +3744,6 @@ static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scop | ... | @@ -3865,14 +3744,6 @@ static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scop |
| 3865 | return result; | 3744 | return result; |
| 3866 | } | 3745 | } |
| 3867 | 3746 | ||
| 3868 | static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope) { | ||
| 3869 | TransScopeSwitch *result = allocate<TransScopeSwitch>(1); | ||
| 3870 | result->base.id = TransScopeIdSwitch; | ||
| 3871 | result->base.parent = parent_scope; | ||
| 3872 | result->switch_node = trans_create_node(c, NodeTypeSwitchExpr); | ||
| 3873 | return result; | ||
| 3874 | } | ||
| 3875 | |||
| 3876 | static TransScopeBlock *trans_scope_block_find(TransScope *scope) { | 3747 | static TransScopeBlock *trans_scope_block_find(TransScope *scope) { |
| 3877 | while (scope != nullptr) { | 3748 | while (scope != nullptr) { |
| 3878 | if (scope->id == TransScopeIdBlock) { | 3749 | if (scope->id == TransScopeIdBlock) { |
| ... | @@ -3883,16 +3754,6 @@ static TransScopeBlock *trans_scope_block_find(TransScope *scope) { | ... | @@ -3883,16 +3754,6 @@ static TransScopeBlock *trans_scope_block_find(TransScope *scope) { |
| 3883 | return nullptr; | 3754 | return nullptr; |
| 3884 | } | 3755 | } |
| 3885 | 3756 | ||
| 3886 | static TransScopeSwitch *trans_scope_switch_find(TransScope *scope) { | ||
| 3887 | while (scope != nullptr) { | ||
| 3888 | if (scope->id == TransScopeIdSwitch) { | ||
| 3889 | return (TransScopeSwitch *)scope; | ||
| 3890 | } | ||
| 3891 | scope = scope->parent; | ||
| 3892 | } | ||
| 3893 | return nullptr; | ||
| 3894 | } | ||
| 3895 | |||
| 3896 | static void render_aliases(Context *c) { | 3757 | static void render_aliases(Context *c) { |
| 3897 | for (size_t i = 0; i < c->aliases.length; i += 1) { | 3758 | for (size_t i = 0; i < c->aliases.length; i += 1) { |
| 3898 | Alias *alias = &c->aliases.at(i); | 3759 | Alias *alias = &c->aliases.at(i); |
| ... | @@ -4003,6 +3864,10 @@ static void render_macros(Context *c) { | ... | @@ -4003,6 +3864,10 @@ static void render_macros(Context *c) { |
| 4003 | } | 3864 | } |
| 4004 | } | 3865 | } |
| 4005 | 3866 | ||
| 3867 | static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok_i); | ||
| 3868 | static AstNode *parse_ctok_expr(Context *c, CTokenize *ctok, size_t *tok_i); | ||
| 3869 | static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i); | ||
| 3870 | |||
| 4006 | static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) { | 3871 | static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) { |
| 4007 | CTok *tok = &ctok->tokens.at(*tok_i); | 3872 | CTok *tok = &ctok->tokens.at(*tok_i); |
| 4008 | if (tok->id == CTokIdNumLitInt) { | 3873 | if (tok->id == CTokIdNumLitInt) { |
| ... | @@ -4030,7 +3895,7 @@ static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, b | ... | @@ -4030,7 +3895,7 @@ static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, b |
| 4030 | return nullptr; | 3895 | return nullptr; |
| 4031 | } | 3896 | } |
| 4032 | 3897 | ||
| 4033 | static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { | 3898 | static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok_i) { |
| 4034 | CTok *tok = &ctok->tokens.at(*tok_i); | 3899 | CTok *tok = &ctok->tokens.at(*tok_i); |
| 4035 | switch (tok->id) { | 3900 | switch (tok->id) { |
| 4036 | case CTokIdCharLit: | 3901 | case CTokIdCharLit: |
| ... | @@ -4047,55 +3912,131 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { | ... | @@ -4047,55 +3912,131 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { |
| 4047 | return parse_ctok_num_lit(c, ctok, tok_i, false); | 3912 | return parse_ctok_num_lit(c, ctok, tok_i, false); |
| 4048 | case CTokIdSymbol: | 3913 | case CTokIdSymbol: |
| 4049 | { | 3914 | { |
| 4050 | bool need_symbol = false; | 3915 | *tok_i += 1; |
| 4051 | CTokId curr_id = CTokIdSymbol; | ||
| 4052 | Buf *symbol_name = buf_create_from_buf(&tok->data.symbol); | 3916 | Buf *symbol_name = buf_create_from_buf(&tok->data.symbol); |
| 4053 | AstNode *curr_node = trans_create_node_symbol(c, symbol_name); | 3917 | return trans_create_node_symbol(c, symbol_name); |
| 4054 | AstNode *parent_node = curr_node; | ||
| 4055 | do { | ||
| 4056 | *tok_i += 1; | ||
| 4057 | CTok* curr_tok = &ctok->tokens.at(*tok_i); | ||
| 4058 | if (need_symbol) { | ||
| 4059 | if (curr_tok->id == CTokIdSymbol) { | ||
| 4060 | symbol_name = buf_create_from_buf(&curr_tok->data.symbol); | ||
| 4061 | curr_node = trans_create_node_field_access(c, parent_node, buf_create_from_buf(symbol_name)); | ||
| 4062 | parent_node = curr_node; | ||
| 4063 | need_symbol = false; | ||
| 4064 | } else { | ||
| 4065 | return nullptr; | ||
| 4066 | } | ||
| 4067 | } else { | ||
| 4068 | if (curr_tok->id == CTokIdDot) { | ||
| 4069 | need_symbol = true; | ||
| 4070 | continue; | ||
| 4071 | } else { | ||
| 4072 | break; | ||
| 4073 | } | ||
| 4074 | } | ||
| 4075 | } while (curr_id != CTokIdEOF); | ||
| 4076 | return curr_node; | ||
| 4077 | } | 3918 | } |
| 4078 | case CTokIdLParen: | 3919 | case CTokIdLParen: |
| 4079 | { | 3920 | { |
| 4080 | *tok_i += 1; | 3921 | *tok_i += 1; |
| 4081 | AstNode *inner_node = parse_ctok(c, ctok, tok_i); | 3922 | AstNode *inner_node = parse_ctok_expr(c, ctok, tok_i); |
| 3923 | if (inner_node == nullptr) { | ||
| 3924 | return nullptr; | ||
| 3925 | } | ||
| 4082 | 3926 | ||
| 4083 | CTok *next_tok = &ctok->tokens.at(*tok_i); | 3927 | CTok *next_tok = &ctok->tokens.at(*tok_i); |
| 4084 | if (next_tok->id != CTokIdRParen) { | 3928 | if (next_tok->id == CTokIdRParen) { |
| 3929 | *tok_i += 1; | ||
| 3930 | return inner_node; | ||
| 3931 | } | ||
| 3932 | |||
| 3933 | AstNode *node_to_cast = parse_ctok_expr(c, ctok, tok_i); | ||
| 3934 | if (node_to_cast == nullptr) { | ||
| 3935 | return nullptr; | ||
| 3936 | } | ||
| 3937 | |||
| 3938 | CTok *next_tok2 = &ctok->tokens.at(*tok_i); | ||
| 3939 | if (next_tok2->id != CTokIdRParen) { | ||
| 4085 | return nullptr; | 3940 | return nullptr; |
| 4086 | } | 3941 | } |
| 4087 | *tok_i += 1; | 3942 | *tok_i += 1; |
| 4088 | return inner_node; | 3943 | |
| 3944 | |||
| 3945 | //if (@typeId(@typeOf(x)) == @import("builtin").TypeId.Pointer) | ||
| 3946 | // @ptrCast(dest, x) | ||
| 3947 | //else if (@typeId(@typeOf(x)) == @import("builtin").TypeId.Integer) | ||
| 3948 | // @intToPtr(dest, x) | ||
| 3949 | //else | ||
| 3950 | // (dest)(x) | ||
| 3951 | |||
| 3952 | AstNode *import_builtin = trans_create_node_builtin_fn_call_str(c, "import"); | ||
| 3953 | import_builtin->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("builtin"))); | ||
| 3954 | AstNode *typeid_type = trans_create_node_field_access_str(c, import_builtin, "TypeId"); | ||
| 3955 | AstNode *typeid_pointer = trans_create_node_field_access_str(c, typeid_type, "Pointer"); | ||
| 3956 | AstNode *typeid_integer = trans_create_node_field_access_str(c, typeid_type, "Int"); | ||
| 3957 | AstNode *typeof_x = trans_create_node_builtin_fn_call_str(c, "typeOf"); | ||
| 3958 | typeof_x->data.fn_call_expr.params.append(node_to_cast); | ||
| 3959 | AstNode *typeid_value = trans_create_node_builtin_fn_call_str(c, "typeId"); | ||
| 3960 | typeid_value->data.fn_call_expr.params.append(typeof_x); | ||
| 3961 | |||
| 3962 | AstNode *outer_if_cond = trans_create_node_bin_op(c, typeid_value, BinOpTypeCmpEq, typeid_pointer); | ||
| 3963 | AstNode *inner_if_cond = trans_create_node_bin_op(c, typeid_value, BinOpTypeCmpEq, typeid_integer); | ||
| 3964 | AstNode *inner_if_then = trans_create_node_builtin_fn_call_str(c, "intToPtr"); | ||
| 3965 | inner_if_then->data.fn_call_expr.params.append(inner_node); | ||
| 3966 | inner_if_then->data.fn_call_expr.params.append(node_to_cast); | ||
| 3967 | AstNode *inner_if_else = trans_create_node_cast(c, inner_node, node_to_cast); | ||
| 3968 | AstNode *inner_if = trans_create_node_if(c, inner_if_cond, inner_if_then, inner_if_else); | ||
| 3969 | AstNode *outer_if_then = trans_create_node_builtin_fn_call_str(c, "ptrCast"); | ||
| 3970 | outer_if_then->data.fn_call_expr.params.append(inner_node); | ||
| 3971 | outer_if_then->data.fn_call_expr.params.append(node_to_cast); | ||
| 3972 | return trans_create_node_if(c, outer_if_cond, outer_if_then, inner_if); | ||
| 4089 | } | 3973 | } |
| 4090 | case CTokIdDot: | 3974 | case CTokIdDot: |
| 4091 | case CTokIdEOF: | 3975 | case CTokIdEOF: |
| 4092 | case CTokIdRParen: | 3976 | case CTokIdRParen: |
| 3977 | case CTokIdAsterisk: | ||
| 3978 | case CTokIdBang: | ||
| 3979 | case CTokIdTilde: | ||
| 4093 | // not able to make sense of this | 3980 | // not able to make sense of this |
| 4094 | return nullptr; | 3981 | return nullptr; |
| 4095 | } | 3982 | } |
| 4096 | zig_unreachable(); | 3983 | zig_unreachable(); |
| 4097 | } | 3984 | } |
| 4098 | 3985 | ||
| 3986 | static AstNode *parse_ctok_expr(Context *c, CTokenize *ctok, size_t *tok_i) { | ||
| 3987 | return parse_ctok_prefix_op_expr(c, ctok, tok_i); | ||
| 3988 | } | ||
| 3989 | |||
| 3990 | static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) { | ||
| 3991 | AstNode *node = parse_ctok_primary_expr(c, ctok, tok_i); | ||
| 3992 | if (node == nullptr) | ||
| 3993 | return nullptr; | ||
| 3994 | |||
| 3995 | while (true) { | ||
| 3996 | CTok *first_tok = &ctok->tokens.at(*tok_i); | ||
| 3997 | if (first_tok->id == CTokIdDot) { | ||
| 3998 | *tok_i += 1; | ||
| 3999 | |||
| 4000 | CTok *name_tok = &ctok->tokens.at(*tok_i); | ||
| 4001 | if (name_tok->id != CTokIdSymbol) { | ||
| 4002 | return nullptr; | ||
| 4003 | } | ||
| 4004 | *tok_i += 1; | ||
| 4005 | |||
| 4006 | node = trans_create_node_field_access(c, node, buf_create_from_buf(&name_tok->data.symbol)); | ||
| 4007 | } else if (first_tok->id == CTokIdAsterisk) { | ||
| 4008 | *tok_i += 1; | ||
| 4009 | |||
| 4010 | node = trans_create_node_addr_of(c, false, false, node); | ||
| 4011 | } else { | ||
| 4012 | return node; | ||
| 4013 | } | ||
| 4014 | } | ||
| 4015 | } | ||
| 4016 | |||
| 4017 | static PrefixOp ctok_to_prefix_op(CTok *token) { | ||
| 4018 | switch (token->id) { | ||
| 4019 | case CTokIdBang: return PrefixOpBoolNot; | ||
| 4020 | case CTokIdMinus: return PrefixOpNegation; | ||
| 4021 | case CTokIdTilde: return PrefixOpBinNot; | ||
| 4022 | case CTokIdAsterisk: return PrefixOpDereference; | ||
| 4023 | default: return PrefixOpInvalid; | ||
| 4024 | } | ||
| 4025 | } | ||
| 4026 | static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) { | ||
| 4027 | CTok *op_tok = &ctok->tokens.at(*tok_i); | ||
| 4028 | PrefixOp prefix_op = ctok_to_prefix_op(op_tok); | ||
| 4029 | if (prefix_op == PrefixOpInvalid) { | ||
| 4030 | return parse_ctok_suffix_op_expr(c, ctok, tok_i); | ||
| 4031 | } | ||
| 4032 | *tok_i += 1; | ||
| 4033 | |||
| 4034 | AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i); | ||
| 4035 | if (prefix_op_expr == nullptr) | ||
| 4036 | return nullptr; | ||
| 4037 | return trans_create_node_prefix_op(c, prefix_op, prefix_op_expr); | ||
| 4038 | } | ||
| 4039 | |||
| 4099 | static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) { | 4040 | static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) { |
| 4100 | tokenize_c_macro(ctok, (const uint8_t *)char_ptr); | 4041 | tokenize_c_macro(ctok, (const uint8_t *)char_ptr); |
| 4101 | 4042 | ||
| ... | @@ -4108,7 +4049,7 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch | ... | @@ -4108,7 +4049,7 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch |
| 4108 | assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name)); | 4049 | assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name)); |
| 4109 | tok_i += 1; | 4050 | tok_i += 1; |
| 4110 | 4051 | ||
| 4111 | AstNode *result_node = parse_ctok(c, ctok, &tok_i); | 4052 | AstNode *result_node = parse_ctok_suffix_op_expr(c, ctok, &tok_i); |
| 4112 | if (result_node == nullptr) { | 4053 | if (result_node == nullptr) { |
| 4113 | return; | 4054 | return; |
| 4114 | } | 4055 | } |
| ... | @@ -4189,10 +4130,10 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch | ... | @@ -4189,10 +4130,10 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch |
| 4189 | c->errors = errors; | 4130 | c->errors = errors; |
| 4190 | if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { | 4131 | if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { |
| 4191 | c->visib_mod = VisibModPub; | 4132 | c->visib_mod = VisibModPub; |
| 4192 | c->export_visib_mod = VisibModPub; | 4133 | c->want_export = false; |
| 4193 | } else { | 4134 | } else { |
| 4194 | c->visib_mod = VisibModPub; | 4135 | c->visib_mod = VisibModPub; |
| 4195 | c->export_visib_mod = VisibModExport; | 4136 | c->want_export = true; |
| 4196 | } | 4137 | } |
| 4197 | c->decl_table.init(8); | 4138 | c->decl_table.init(8); |
| 4198 | c->macro_table.init(8); | 4139 | c->macro_table.init(8); |
src/zig_llvm.cpp+10-3| ... | @@ -175,12 +175,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -175,12 +175,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 175 | 175 | ||
| 176 | 176 | ||
| 177 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, | 177 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, |
| 178 | unsigned NumArgs, unsigned CC, bool always_inline, const char *Name) | 178 | unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name) |
| 179 | { | 179 | { |
| 180 | CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name); | 180 | CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name); |
| 181 | call_inst->setCallingConv(CC); | 181 | call_inst->setCallingConv(CC); |
| 182 | if (always_inline) { | 182 | switch (fn_inline) { |
| 183 | call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline); | 183 | case ZigLLVM_FnInlineAuto: |
| 184 | break; | ||
| 185 | case ZigLLVM_FnInlineAlways: | ||
| 186 | call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline); | ||
| 187 | break; | ||
| 188 | case ZigLLVM_FnInlineNever: | ||
| 189 | call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::NoInline); | ||
| 190 | break; | ||
| 184 | } | 191 | } |
| 185 | return wrap(unwrap(B)->Insert(call_inst)); | 192 | return wrap(unwrap(B)->Insert(call_inst)); |
| 186 | } | 193 | } |
src/zig_llvm.hpp+6-1| ... | @@ -45,8 +45,13 @@ enum ZigLLVM_EmitOutputType { | ... | @@ -45,8 +45,13 @@ enum ZigLLVM_EmitOutputType { |
| 45 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, | 45 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, |
| 46 | const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug); | 46 | const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug); |
| 47 | 47 | ||
| 48 | enum ZigLLVM_FnInline { | ||
| 49 | ZigLLVM_FnInlineAuto, | ||
| 50 | ZigLLVM_FnInlineAlways, | ||
| 51 | ZigLLVM_FnInlineNever, | ||
| 52 | }; | ||
| 48 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, | 53 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, |
| 49 | unsigned NumArgs, unsigned CC, bool always_inline, const char *Name); | 54 | unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name); |
| 50 | 55 | ||
| 51 | LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, | 56 | LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, |
| 52 | LLVMValueRef new_val, LLVMAtomicOrdering success_ordering, | 57 | LLVMValueRef new_val, LLVMAtomicOrdering success_ordering, |
std/array_list.zig+24-14| ... | @@ -3,42 +3,46 @@ const assert = debug.assert; | ... | @@ -3,42 +3,46 @@ const assert = debug.assert; |
| 3 | const mem = @import("mem.zig"); | 3 | const mem = @import("mem.zig"); |
| 4 | const Allocator = mem.Allocator; | 4 | const Allocator = mem.Allocator; |
| 5 | 5 | ||
| 6 | pub fn ArrayList(comptime T: type) -> type{ | 6 | pub fn ArrayList(comptime T: type) -> type { |
| 7 | struct { | 7 | return AlignedArrayList(T, @alignOf(T)); |
| 8 | } | ||
| 9 | |||
| 10 | pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{ | ||
| 11 | return struct { | ||
| 8 | const Self = this; | 12 | const Self = this; |
| 9 | 13 | ||
| 10 | /// Use toSlice instead of slicing this directly, because if you don't | 14 | /// Use toSlice instead of slicing this directly, because if you don't |
| 11 | /// specify the end position of the slice, this will potentially give | 15 | /// specify the end position of the slice, this will potentially give |
| 12 | /// you uninitialized memory. | 16 | /// you uninitialized memory. |
| 13 | items: []T, | 17 | items: []align(A) T, |
| 14 | len: usize, | 18 | len: usize, |
| 15 | allocator: &Allocator, | 19 | allocator: &Allocator, |
| 16 | 20 | ||
| 17 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | 21 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| 18 | pub fn init(allocator: &Allocator) -> Self { | 22 | pub fn init(allocator: &Allocator) -> Self { |
| 19 | Self { | 23 | return Self { |
| 20 | .items = []T{}, | 24 | .items = []align(A) T{}, |
| 21 | .len = 0, | 25 | .len = 0, |
| 22 | .allocator = allocator, | 26 | .allocator = allocator, |
| 23 | } | 27 | }; |
| 24 | } | 28 | } |
| 25 | 29 | ||
| 26 | pub fn deinit(l: &Self) { | 30 | pub fn deinit(l: &Self) { |
| 27 | l.allocator.free(l.items); | 31 | l.allocator.free(l.items); |
| 28 | } | 32 | } |
| 29 | 33 | ||
| 30 | pub fn toSlice(l: &Self) -> []T { | 34 | pub fn toSlice(l: &Self) -> []align(A) T { |
| 31 | return l.items[0..l.len]; | 35 | return l.items[0..l.len]; |
| 32 | } | 36 | } |
| 33 | 37 | ||
| 34 | pub fn toSliceConst(l: &const Self) -> []const T { | 38 | pub fn toSliceConst(l: &const Self) -> []align(A) const T { |
| 35 | return l.items[0..l.len]; | 39 | return l.items[0..l.len]; |
| 36 | } | 40 | } |
| 37 | 41 | ||
| 38 | /// ArrayList takes ownership of the passed in slice. The slice must have been | 42 | /// ArrayList takes ownership of the passed in slice. The slice must have been |
| 39 | /// allocated with `allocator`. | 43 | /// allocated with `allocator`. |
| 40 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | 44 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| 41 | pub fn fromOwnedSlice(allocator: &Allocator, slice: []T) -> Self { | 45 | pub fn fromOwnedSlice(allocator: &Allocator, slice: []align(A) T) -> Self { |
| 42 | return Self { | 46 | return Self { |
| 43 | .items = slice, | 47 | .items = slice, |
| 44 | .len = slice.len, | 48 | .len = slice.len, |
| ... | @@ -47,9 +51,9 @@ pub fn ArrayList(comptime T: type) -> type{ | ... | @@ -47,9 +51,9 @@ pub fn ArrayList(comptime T: type) -> type{ |
| 47 | } | 51 | } |
| 48 | 52 | ||
| 49 | /// The caller owns the returned memory. ArrayList becomes empty. | 53 | /// The caller owns the returned memory. ArrayList becomes empty. |
| 50 | pub fn toOwnedSlice(self: &Self) -> []T { | 54 | pub fn toOwnedSlice(self: &Self) -> []align(A) T { |
| 51 | const allocator = self.allocator; | 55 | const allocator = self.allocator; |
| 52 | const result = allocator.shrink(T, self.items, self.len); | 56 | const result = allocator.alignedShrink(T, A, self.items, self.len); |
| 53 | *self = init(allocator); | 57 | *self = init(allocator); |
| 54 | return result; | 58 | return result; |
| 55 | } | 59 | } |
| ... | @@ -59,7 +63,7 @@ pub fn ArrayList(comptime T: type) -> type{ | ... | @@ -59,7 +63,7 @@ pub fn ArrayList(comptime T: type) -> type{ |
| 59 | *new_item_ptr = *item; | 63 | *new_item_ptr = *item; |
| 60 | } | 64 | } |
| 61 | 65 | ||
| 62 | pub fn appendSlice(l: &Self, items: []const T) -> %void { | 66 | pub fn appendSlice(l: &Self, items: []align(A) const T) -> %void { |
| 63 | %return l.ensureCapacity(l.len + items.len); | 67 | %return l.ensureCapacity(l.len + items.len); |
| 64 | mem.copy(T, l.items[l.len..], items); | 68 | mem.copy(T, l.items[l.len..], items); |
| 65 | l.len += items.len; | 69 | l.len += items.len; |
| ... | @@ -82,7 +86,7 @@ pub fn ArrayList(comptime T: type) -> type{ | ... | @@ -82,7 +86,7 @@ pub fn ArrayList(comptime T: type) -> type{ |
| 82 | better_capacity += better_capacity / 2 + 8; | 86 | better_capacity += better_capacity / 2 + 8; |
| 83 | if (better_capacity >= new_capacity) break; | 87 | if (better_capacity >= new_capacity) break; |
| 84 | } | 88 | } |
| 85 | l.items = %return l.allocator.realloc(T, l.items, better_capacity); | 89 | l.items = %return l.allocator.alignedRealloc(T, A, l.items, better_capacity); |
| 86 | } | 90 | } |
| 87 | 91 | ||
| 88 | pub fn addOne(l: &Self) -> %&T { | 92 | pub fn addOne(l: &Self) -> %&T { |
| ... | @@ -97,7 +101,13 @@ pub fn ArrayList(comptime T: type) -> type{ | ... | @@ -97,7 +101,13 @@ pub fn ArrayList(comptime T: type) -> type{ |
| 97 | self.len -= 1; | 101 | self.len -= 1; |
| 98 | return self.items[self.len]; | 102 | return self.items[self.len]; |
| 99 | } | 103 | } |
| 100 | } | 104 | |
| 105 | pub fn popOrNull(self: &Self) -> ?T { | ||
| 106 | if (self.len == 0) | ||
| 107 | return null; | ||
| 108 | return self.pop(); | ||
| 109 | } | ||
| 110 | }; | ||
| 101 | } | 111 | } |
| 102 | 112 | ||
| 103 | test "basic ArrayList test" { | 113 | test "basic ArrayList test" { |
std/base64.zig+1-1| ... | @@ -193,7 +193,7 @@ pub const Base64DecoderWithIgnore = struct { | ... | @@ -193,7 +193,7 @@ pub const Base64DecoderWithIgnore = struct { |
| 193 | /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound. | 193 | /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound. |
| 194 | /// Returns the number of bytes writen to dest. | 194 | /// Returns the number of bytes writen to dest. |
| 195 | pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) -> %usize { | 195 | pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) -> %usize { |
| 196 | const decoder = &const decoder_with_ignore.decoder; | 196 | const decoder = &decoder_with_ignore.decoder; |
| 197 | 197 | ||
| 198 | var src_cursor: usize = 0; | 198 | var src_cursor: usize = 0; |
| 199 | var dest_cursor: usize = 0; | 199 | var dest_cursor: usize = 0; |
std/buf_map.zig+5| ... | @@ -42,6 +42,11 @@ pub const BufMap = struct { | ... | @@ -42,6 +42,11 @@ pub const BufMap = struct { |
| 42 | } | 42 | } |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | pub fn get(self: &BufMap, key: []const u8) -> ?[]const u8 { | ||
| 46 | const entry = self.hash_map.get(key) ?? return null; | ||
| 47 | return entry.value; | ||
| 48 | } | ||
| 49 | |||
| 45 | pub fn delete(self: &BufMap, key: []const u8) { | 50 | pub fn delete(self: &BufMap, key: []const u8) { |
| 46 | const entry = self.hash_map.remove(key) ?? return; | 51 | const entry = self.hash_map.remove(key) ?? return; |
| 47 | self.free(entry.key); | 52 | self.free(entry.key); |
std/buffer.zig+11-3| ... | @@ -30,9 +30,9 @@ pub const Buffer = struct { | ... | @@ -30,9 +30,9 @@ pub const Buffer = struct { |
| 30 | /// * ::replaceContentsBuffer | 30 | /// * ::replaceContentsBuffer |
| 31 | /// * ::resize | 31 | /// * ::resize |
| 32 | pub fn initNull(allocator: &Allocator) -> Buffer { | 32 | pub fn initNull(allocator: &Allocator) -> Buffer { |
| 33 | Buffer { | 33 | return Buffer { |
| 34 | .list = ArrayList(u8).init(allocator), | 34 | .list = ArrayList(u8).init(allocator), |
| 35 | } | 35 | }; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | /// Must deinitialize with deinit. | 38 | /// Must deinitialize with deinit. |
| ... | @@ -98,14 +98,17 @@ pub const Buffer = struct { | ... | @@ -98,14 +98,17 @@ pub const Buffer = struct { |
| 98 | mem.copy(u8, self.list.toSlice()[old_len..], m); | 98 | mem.copy(u8, self.list.toSlice()[old_len..], m); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | // TODO: remove, use OutStream for this | ||
| 101 | pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) -> %void { | 102 | pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) -> %void { |
| 102 | return fmt.format(self, append, format, args); | 103 | return fmt.format(self, append, format, args); |
| 103 | } | 104 | } |
| 104 | 105 | ||
| 106 | // TODO: remove, use OutStream for this | ||
| 105 | pub fn appendByte(self: &Buffer, byte: u8) -> %void { | 107 | pub fn appendByte(self: &Buffer, byte: u8) -> %void { |
| 106 | return self.appendByteNTimes(byte, 1); | 108 | return self.appendByteNTimes(byte, 1); |
| 107 | } | 109 | } |
| 108 | 110 | ||
| 111 | // TODO: remove, use OutStream for this | ||
| 109 | pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) -> %void { | 112 | pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) -> %void { |
| 110 | var prev_size: usize = self.len(); | 113 | var prev_size: usize = self.len(); |
| 111 | %return self.resize(prev_size + count); | 114 | %return self.resize(prev_size + count); |
| ... | @@ -117,7 +120,7 @@ pub const Buffer = struct { | ... | @@ -117,7 +120,7 @@ pub const Buffer = struct { |
| 117 | } | 120 | } |
| 118 | 121 | ||
| 119 | pub fn eql(self: &const Buffer, m: []const u8) -> bool { | 122 | pub fn eql(self: &const Buffer, m: []const u8) -> bool { |
| 120 | mem.eql(u8, self.toSliceConst(), m) | 123 | return mem.eql(u8, self.toSliceConst(), m); |
| 121 | } | 124 | } |
| 122 | 125 | ||
| 123 | pub fn startsWith(self: &const Buffer, m: []const u8) -> bool { | 126 | pub fn startsWith(self: &const Buffer, m: []const u8) -> bool { |
| ... | @@ -136,6 +139,11 @@ pub const Buffer = struct { | ... | @@ -136,6 +139,11 @@ pub const Buffer = struct { |
| 136 | %return self.resize(m.len); | 139 | %return self.resize(m.len); |
| 137 | mem.copy(u8, self.list.toSlice(), m); | 140 | mem.copy(u8, self.list.toSlice(), m); |
| 138 | } | 141 | } |
| 142 | |||
| 143 | /// For passing to C functions. | ||
| 144 | pub fn ptr(self: &const Buffer) -> &u8 { | ||
| 145 | return self.list.items.ptr; | ||
| 146 | } | ||
| 139 | }; | 147 | }; |
| 140 | 148 | ||
| 141 | test "simple Buffer" { | 149 | test "simple Buffer" { |
std/build.zig+102-32| ... | @@ -221,11 +221,11 @@ pub const Builder = struct { | ... | @@ -221,11 +221,11 @@ pub const Builder = struct { |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version { | 223 | pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version { |
| 224 | Version { | 224 | return Version { |
| 225 | .major = major, | 225 | .major = major, |
| 226 | .minor = minor, | 226 | .minor = minor, |
| 227 | .patch = patch, | 227 | .patch = patch, |
| 228 | } | 228 | }; |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | pub fn addCIncludePath(self: &Builder, path: []const u8) { | 231 | pub fn addCIncludePath(self: &Builder, path: []const u8) { |
| ... | @@ -432,16 +432,16 @@ pub const Builder = struct { | ... | @@ -432,16 +432,16 @@ pub const Builder = struct { |
| 432 | const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false; | 432 | const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false; |
| 433 | const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false; | 433 | const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false; |
| 434 | 434 | ||
| 435 | const mode = if (release_safe and !release_fast) { | 435 | const mode = if (release_safe and !release_fast) |
| 436 | builtin.Mode.ReleaseSafe | 436 | builtin.Mode.ReleaseSafe |
| 437 | } else if (release_fast and !release_safe) { | 437 | else if (release_fast and !release_safe) |
| 438 | builtin.Mode.ReleaseFast | 438 | builtin.Mode.ReleaseFast |
| 439 | } else if (!release_fast and !release_safe) { | 439 | else if (!release_fast and !release_safe) |
| 440 | builtin.Mode.Debug | 440 | builtin.Mode.Debug |
| 441 | } else { | 441 | else x: { |
| 442 | warn("Both -Drelease-safe and -Drelease-fast specified"); | 442 | warn("Both -Drelease-safe and -Drelease-fast specified"); |
| 443 | self.markInvalidUserInput(); | 443 | self.markInvalidUserInput(); |
| 444 | builtin.Mode.Debug | 444 | break :x builtin.Mode.Debug; |
| 445 | }; | 445 | }; |
| 446 | self.release_mode = mode; | 446 | self.release_mode = mode; |
| 447 | return mode; | 447 | return mode; |
| ... | @@ -506,7 +506,7 @@ pub const Builder = struct { | ... | @@ -506,7 +506,7 @@ pub const Builder = struct { |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | fn typeToEnum(comptime T: type) -> TypeId { | 508 | fn typeToEnum(comptime T: type) -> TypeId { |
| 509 | switch (@typeId(T)) { | 509 | return switch (@typeId(T)) { |
| 510 | builtin.TypeId.Int => TypeId.Int, | 510 | builtin.TypeId.Int => TypeId.Int, |
| 511 | builtin.TypeId.Float => TypeId.Float, | 511 | builtin.TypeId.Float => TypeId.Float, |
| 512 | builtin.TypeId.Bool => TypeId.Bool, | 512 | builtin.TypeId.Bool => TypeId.Bool, |
| ... | @@ -515,7 +515,7 @@ pub const Builder = struct { | ... | @@ -515,7 +515,7 @@ pub const Builder = struct { |
| 515 | []const []const u8 => TypeId.List, | 515 | []const []const u8 => TypeId.List, |
| 516 | else => @compileError("Unsupported type: " ++ @typeName(T)), | 516 | else => @compileError("Unsupported type: " ++ @typeName(T)), |
| 517 | }, | 517 | }, |
| 518 | } | 518 | }; |
| 519 | } | 519 | } |
| 520 | 520 | ||
| 521 | fn markInvalidUserInput(self: &Builder) { | 521 | fn markInvalidUserInput(self: &Builder) { |
| ... | @@ -590,8 +590,7 @@ pub const Builder = struct { | ... | @@ -590,8 +590,7 @@ pub const Builder = struct { |
| 590 | 590 | ||
| 591 | return error.UncleanExit; | 591 | return error.UncleanExit; |
| 592 | }, | 592 | }, |
| 593 | }; | 593 | } |
| 594 | |||
| 595 | } | 594 | } |
| 596 | 595 | ||
| 597 | pub fn makePath(self: &Builder, path: []const u8) -> %void { | 596 | pub fn makePath(self: &Builder, path: []const u8) -> %void { |
| ... | @@ -662,13 +661,70 @@ pub const Builder = struct { | ... | @@ -662,13 +661,70 @@ pub const Builder = struct { |
| 662 | if (builtin.environ == builtin.Environ.msvc) { | 661 | if (builtin.environ == builtin.Environ.msvc) { |
| 663 | return "cl.exe"; | 662 | return "cl.exe"; |
| 664 | } else { | 663 | } else { |
| 665 | return os.getEnvVarOwned(self.allocator, "CC") %% |err| { | 664 | return os.getEnvVarOwned(self.allocator, "CC") %% |err| |
| 666 | if (err == error.EnvironmentVariableNotFound) { | 665 | if (err == error.EnvironmentVariableNotFound) |
| 667 | ([]const u8)("cc") | 666 | ([]const u8)("cc") |
| 668 | } else { | 667 | else |
| 669 | debug.panic("Unable to get environment variable: {}", err); | 668 | debug.panic("Unable to get environment variable: {}", err) |
| 669 | ; | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 673 | pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) -> %[]const u8 { | ||
| 674 | const exe_extension = (Target { .Native = {}}).exeFileExt(); | ||
| 675 | if (self.env_map.get("PATH")) |PATH| { | ||
| 676 | for (names) |name| { | ||
| 677 | if (os.path.isAbsolute(name)) { | ||
| 678 | return name; | ||
| 670 | } | 679 | } |
| 671 | }; | 680 | var it = mem.split(PATH, []u8{os.path.delimiter}); |
| 681 | while (it.next()) |path| { | ||
| 682 | const full_path = %return os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension)); | ||
| 683 | if (os.path.real(self.allocator, full_path)) |real_path| { | ||
| 684 | return real_path; | ||
| 685 | } else |_| { | ||
| 686 | continue; | ||
| 687 | } | ||
| 688 | } | ||
| 689 | } | ||
| 690 | } | ||
| 691 | for (names) |name| { | ||
| 692 | if (os.path.isAbsolute(name)) { | ||
| 693 | return name; | ||
| 694 | } | ||
| 695 | for (paths) |path| { | ||
| 696 | const full_path = %return os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension)); | ||
| 697 | if (os.path.real(self.allocator, full_path)) |real_path| { | ||
| 698 | return real_path; | ||
| 699 | } else |_| { | ||
| 700 | continue; | ||
| 701 | } | ||
| 702 | } | ||
| 703 | } | ||
| 704 | return error.FileNotFound; | ||
| 705 | } | ||
| 706 | |||
| 707 | pub fn exec(self: &Builder, argv: []const []const u8) -> []u8 { | ||
| 708 | const max_output_size = 100 * 1024; | ||
| 709 | const result = os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size) %% |err| { | ||
| 710 | std.debug.panic("Unable to spawn {}: {}", argv[0], @errorName(err)); | ||
| 711 | }; | ||
| 712 | switch (result.term) { | ||
| 713 | os.ChildProcess.Term.Exited => |code| { | ||
| 714 | if (code != 0) { | ||
| 715 | warn("The following command exited with error code {}:\n", code); | ||
| 716 | printCmd(null, argv); | ||
| 717 | warn("stderr:{}\n", result.stderr); | ||
| 718 | std.debug.panic("command failed"); | ||
| 719 | } | ||
| 720 | return result.stdout; | ||
| 721 | }, | ||
| 722 | else => { | ||
| 723 | warn("The following command terminated unexpectedly:\n"); | ||
| 724 | printCmd(null, argv); | ||
| 725 | warn("stderr:{}\n", result.stderr); | ||
| 726 | std.debug.panic("command failed"); | ||
| 727 | }, | ||
| 672 | } | 728 | } |
| 673 | } | 729 | } |
| 674 | }; | 730 | }; |
| ... | @@ -755,6 +811,7 @@ pub const LibExeObjStep = struct { | ... | @@ -755,6 +811,7 @@ pub const LibExeObjStep = struct { |
| 755 | is_zig: bool, | 811 | is_zig: bool, |
| 756 | cflags: ArrayList([]const u8), | 812 | cflags: ArrayList([]const u8), |
| 757 | include_dirs: ArrayList([]const u8), | 813 | include_dirs: ArrayList([]const u8), |
| 814 | lib_paths: ArrayList([]const u8), | ||
| 758 | disable_libc: bool, | 815 | disable_libc: bool, |
| 759 | frameworks: BufSet, | 816 | frameworks: BufSet, |
| 760 | 817 | ||
| ... | @@ -844,7 +901,7 @@ pub const LibExeObjStep = struct { | ... | @@ -844,7 +901,7 @@ pub const LibExeObjStep = struct { |
| 844 | .kind = kind, | 901 | .kind = kind, |
| 845 | .root_src = root_src, | 902 | .root_src = root_src, |
| 846 | .name = name, | 903 | .name = name, |
| 847 | .target = Target { .Native = {} }, | 904 | .target = Target.Native, |
| 848 | .linker_script = null, | 905 | .linker_script = null, |
| 849 | .link_libs = BufSet.init(builder.allocator), | 906 | .link_libs = BufSet.init(builder.allocator), |
| 850 | .frameworks = BufSet.init(builder.allocator), | 907 | .frameworks = BufSet.init(builder.allocator), |
| ... | @@ -865,6 +922,7 @@ pub const LibExeObjStep = struct { | ... | @@ -865,6 +922,7 @@ pub const LibExeObjStep = struct { |
| 865 | .cflags = ArrayList([]const u8).init(builder.allocator), | 922 | .cflags = ArrayList([]const u8).init(builder.allocator), |
| 866 | .source_files = undefined, | 923 | .source_files = undefined, |
| 867 | .include_dirs = ArrayList([]const u8).init(builder.allocator), | 924 | .include_dirs = ArrayList([]const u8).init(builder.allocator), |
| 925 | .lib_paths = ArrayList([]const u8).init(builder.allocator), | ||
| 868 | .object_src = undefined, | 926 | .object_src = undefined, |
| 869 | .disable_libc = true, | 927 | .disable_libc = true, |
| 870 | }; | 928 | }; |
| ... | @@ -879,7 +937,7 @@ pub const LibExeObjStep = struct { | ... | @@ -879,7 +937,7 @@ pub const LibExeObjStep = struct { |
| 879 | .kind = kind, | 937 | .kind = kind, |
| 880 | .version = *version, | 938 | .version = *version, |
| 881 | .static = static, | 939 | .static = static, |
| 882 | .target = Target { .Native = {} }, | 940 | .target = Target.Native, |
| 883 | .cflags = ArrayList([]const u8).init(builder.allocator), | 941 | .cflags = ArrayList([]const u8).init(builder.allocator), |
| 884 | .source_files = ArrayList([]const u8).init(builder.allocator), | 942 | .source_files = ArrayList([]const u8).init(builder.allocator), |
| 885 | .object_files = ArrayList([]const u8).init(builder.allocator), | 943 | .object_files = ArrayList([]const u8).init(builder.allocator), |
| ... | @@ -888,6 +946,7 @@ pub const LibExeObjStep = struct { | ... | @@ -888,6 +946,7 @@ pub const LibExeObjStep = struct { |
| 888 | .frameworks = BufSet.init(builder.allocator), | 946 | .frameworks = BufSet.init(builder.allocator), |
| 889 | .full_path_libs = ArrayList([]const u8).init(builder.allocator), | 947 | .full_path_libs = ArrayList([]const u8).init(builder.allocator), |
| 890 | .include_dirs = ArrayList([]const u8).init(builder.allocator), | 948 | .include_dirs = ArrayList([]const u8).init(builder.allocator), |
| 949 | .lib_paths = ArrayList([]const u8).init(builder.allocator), | ||
| 891 | .output_path = null, | 950 | .output_path = null, |
| 892 | .out_filename = undefined, | 951 | .out_filename = undefined, |
| 893 | .major_only_filename = undefined, | 952 | .major_only_filename = undefined, |
| ... | @@ -1018,11 +1077,10 @@ pub const LibExeObjStep = struct { | ... | @@ -1018,11 +1077,10 @@ pub const LibExeObjStep = struct { |
| 1018 | } | 1077 | } |
| 1019 | 1078 | ||
| 1020 | pub fn getOutputPath(self: &LibExeObjStep) -> []const u8 { | 1079 | pub fn getOutputPath(self: &LibExeObjStep) -> []const u8 { |
| 1021 | if (self.output_path) |output_path| { | 1080 | return if (self.output_path) |output_path| |
| 1022 | output_path | 1081 | output_path |
| 1023 | } else { | 1082 | else |
| 1024 | %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename) | 1083 | %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename); |
| 1025 | } | ||
| 1026 | } | 1084 | } |
| 1027 | 1085 | ||
| 1028 | pub fn setOutputHPath(self: &LibExeObjStep, file_path: []const u8) { | 1086 | pub fn setOutputHPath(self: &LibExeObjStep, file_path: []const u8) { |
| ... | @@ -1035,11 +1093,10 @@ pub const LibExeObjStep = struct { | ... | @@ -1035,11 +1093,10 @@ pub const LibExeObjStep = struct { |
| 1035 | } | 1093 | } |
| 1036 | 1094 | ||
| 1037 | pub fn getOutputHPath(self: &LibExeObjStep) -> []const u8 { | 1095 | pub fn getOutputHPath(self: &LibExeObjStep) -> []const u8 { |
| 1038 | if (self.output_h_path) |output_h_path| { | 1096 | return if (self.output_h_path) |output_h_path| |
| 1039 | output_h_path | 1097 | output_h_path |
| 1040 | } else { | 1098 | else |
| 1041 | %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename) | 1099 | %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename); |
| 1042 | } | ||
| 1043 | } | 1100 | } |
| 1044 | 1101 | ||
| 1045 | pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) { | 1102 | pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) { |
| ... | @@ -1069,11 +1126,14 @@ pub const LibExeObjStep = struct { | ... | @@ -1069,11 +1126,14 @@ pub const LibExeObjStep = struct { |
| 1069 | %%self.include_dirs.append(self.builder.cache_root); | 1126 | %%self.include_dirs.append(self.builder.cache_root); |
| 1070 | } | 1127 | } |
| 1071 | 1128 | ||
| 1072 | // TODO put include_dirs in zig command line | ||
| 1073 | pub fn addIncludeDir(self: &LibExeObjStep, path: []const u8) { | 1129 | pub fn addIncludeDir(self: &LibExeObjStep, path: []const u8) { |
| 1074 | %%self.include_dirs.append(path); | 1130 | %%self.include_dirs.append(path); |
| 1075 | } | 1131 | } |
| 1076 | 1132 | ||
| 1133 | pub fn addLibPath(self: &LibExeObjStep, path: []const u8) { | ||
| 1134 | %%self.lib_paths.append(path); | ||
| 1135 | } | ||
| 1136 | |||
| 1077 | pub fn addPackagePath(self: &LibExeObjStep, name: []const u8, pkg_index_path: []const u8) { | 1137 | pub fn addPackagePath(self: &LibExeObjStep, name: []const u8, pkg_index_path: []const u8) { |
| 1078 | assert(self.is_zig); | 1138 | assert(self.is_zig); |
| 1079 | 1139 | ||
| ... | @@ -1222,6 +1282,11 @@ pub const LibExeObjStep = struct { | ... | @@ -1222,6 +1282,11 @@ pub const LibExeObjStep = struct { |
| 1222 | %%zig_args.append("--pkg-end"); | 1282 | %%zig_args.append("--pkg-end"); |
| 1223 | } | 1283 | } |
| 1224 | 1284 | ||
| 1285 | for (self.include_dirs.toSliceConst()) |include_path| { | ||
| 1286 | %%zig_args.append("-isystem"); | ||
| 1287 | %%zig_args.append(self.builder.pathFromRoot(include_path)); | ||
| 1288 | } | ||
| 1289 | |||
| 1225 | for (builder.include_paths.toSliceConst()) |include_path| { | 1290 | for (builder.include_paths.toSliceConst()) |include_path| { |
| 1226 | %%zig_args.append("-isystem"); | 1291 | %%zig_args.append("-isystem"); |
| 1227 | %%zig_args.append(builder.pathFromRoot(include_path)); | 1292 | %%zig_args.append(builder.pathFromRoot(include_path)); |
| ... | @@ -1232,6 +1297,11 @@ pub const LibExeObjStep = struct { | ... | @@ -1232,6 +1297,11 @@ pub const LibExeObjStep = struct { |
| 1232 | %%zig_args.append(rpath); | 1297 | %%zig_args.append(rpath); |
| 1233 | } | 1298 | } |
| 1234 | 1299 | ||
| 1300 | for (self.lib_paths.toSliceConst()) |lib_path| { | ||
| 1301 | %%zig_args.append("--library-path"); | ||
| 1302 | %%zig_args.append(lib_path); | ||
| 1303 | } | ||
| 1304 | |||
| 1235 | for (builder.lib_paths.toSliceConst()) |lib_path| { | 1305 | for (builder.lib_paths.toSliceConst()) |lib_path| { |
| 1236 | %%zig_args.append("--library-path"); | 1306 | %%zig_args.append("--library-path"); |
| 1237 | %%zig_args.append(lib_path); | 1307 | %%zig_args.append(lib_path); |
| ... | @@ -1544,7 +1614,7 @@ pub const TestStep = struct { | ... | @@ -1544,7 +1614,7 @@ pub const TestStep = struct { |
| 1544 | 1614 | ||
| 1545 | pub fn init(builder: &Builder, root_src: []const u8) -> TestStep { | 1615 | pub fn init(builder: &Builder, root_src: []const u8) -> TestStep { |
| 1546 | const step_name = builder.fmt("test {}", root_src); | 1616 | const step_name = builder.fmt("test {}", root_src); |
| 1547 | TestStep { | 1617 | return TestStep { |
| 1548 | .step = Step.init(step_name, builder.allocator, make), | 1618 | .step = Step.init(step_name, builder.allocator, make), |
| 1549 | .builder = builder, | 1619 | .builder = builder, |
| 1550 | .root_src = root_src, | 1620 | .root_src = root_src, |
| ... | @@ -1555,7 +1625,7 @@ pub const TestStep = struct { | ... | @@ -1555,7 +1625,7 @@ pub const TestStep = struct { |
| 1555 | .link_libs = BufSet.init(builder.allocator), | 1625 | .link_libs = BufSet.init(builder.allocator), |
| 1556 | .target = Target { .Native = {} }, | 1626 | .target = Target { .Native = {} }, |
| 1557 | .exec_cmd_args = null, | 1627 | .exec_cmd_args = null, |
| 1558 | } | 1628 | }; |
| 1559 | } | 1629 | } |
| 1560 | 1630 | ||
| 1561 | pub fn setVerbose(self: &TestStep, value: bool) { | 1631 | pub fn setVerbose(self: &TestStep, value: bool) { |
| ... | @@ -1862,16 +1932,16 @@ pub const Step = struct { | ... | @@ -1862,16 +1932,16 @@ pub const Step = struct { |
| 1862 | done_flag: bool, | 1932 | done_flag: bool, |
| 1863 | 1933 | ||
| 1864 | pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)->%void) -> Step { | 1934 | pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)->%void) -> Step { |
| 1865 | Step { | 1935 | return Step { |
| 1866 | .name = name, | 1936 | .name = name, |
| 1867 | .makeFn = makeFn, | 1937 | .makeFn = makeFn, |
| 1868 | .dependencies = ArrayList(&Step).init(allocator), | 1938 | .dependencies = ArrayList(&Step).init(allocator), |
| 1869 | .loop_flag = false, | 1939 | .loop_flag = false, |
| 1870 | .done_flag = false, | 1940 | .done_flag = false, |
| 1871 | } | 1941 | }; |
| 1872 | } | 1942 | } |
| 1873 | pub fn initNoOp(name: []const u8, allocator: &Allocator) -> Step { | 1943 | pub fn initNoOp(name: []const u8, allocator: &Allocator) -> Step { |
| 1874 | init(name, allocator, makeNoOp) | 1944 | return init(name, allocator, makeNoOp); |
| 1875 | } | 1945 | } |
| 1876 | 1946 | ||
| 1877 | pub fn make(self: &Step) -> %void { | 1947 | pub fn make(self: &Step) -> %void { |
std/c/index.zig+1| ... | @@ -48,3 +48,4 @@ pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) -> c_int; | ... | @@ -48,3 +48,4 @@ pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) -> c_int; |
| 48 | pub extern "c" fn malloc(usize) -> ?&c_void; | 48 | pub extern "c" fn malloc(usize) -> ?&c_void; |
| 49 | pub extern "c" fn realloc(&c_void, usize) -> ?&c_void; | 49 | pub extern "c" fn realloc(&c_void, usize) -> ?&c_void; |
| 50 | pub extern "c" fn free(&c_void); | 50 | pub extern "c" fn free(&c_void); |
| 51 | pub extern "c" fn posix_memalign(memptr: &&c_void, alignment: usize, size: usize) -> c_int; |
std/cstr.zig+1-1| ... | @@ -17,7 +17,7 @@ pub fn cmp(a: &const u8, b: &const u8) -> i8 { | ... | @@ -17,7 +17,7 @@ pub fn cmp(a: &const u8, b: &const u8) -> i8 { |
| 17 | return -1; | 17 | return -1; |
| 18 | } else { | 18 | } else { |
| 19 | return 0; | 19 | return 0; |
| 20 | }; | 20 | } |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | pub fn toSliceConst(str: &const u8) -> []const u8 { | 23 | pub fn toSliceConst(str: &const u8) -> []const u8 { |
std/debug.zig+130-84| ... | @@ -32,7 +32,7 @@ fn getStderrStream() -> %&io.OutStream { | ... | @@ -32,7 +32,7 @@ fn getStderrStream() -> %&io.OutStream { |
| 32 | const st = &stderr_file_out_stream.stream; | 32 | const st = &stderr_file_out_stream.stream; |
| 33 | stderr_stream = st; | 33 | stderr_stream = st; |
| 34 | return st; | 34 | return st; |
| 35 | }; | 35 | } |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. | 38 | /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. |
| ... | @@ -52,9 +52,9 @@ pub fn assert(ok: bool) { | ... | @@ -52,9 +52,9 @@ pub fn assert(ok: bool) { |
| 52 | // we insert an explicit call to @panic instead of unreachable. | 52 | // we insert an explicit call to @panic instead of unreachable. |
| 53 | // TODO we should use `assertOrPanic` in tests and remove this logic. | 53 | // TODO we should use `assertOrPanic` in tests and remove this logic. |
| 54 | if (builtin.is_test) { | 54 | if (builtin.is_test) { |
| 55 | @panic("assertion failure") | 55 | @panic("assertion failure"); |
| 56 | } else { | 56 | } else { |
| 57 | unreachable // assertion failure | 57 | unreachable; // assertion failure |
| 58 | } | 58 | } |
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| ... | @@ -96,8 +96,6 @@ const WHITE = "\x1b[37;1m"; | ... | @@ -96,8 +96,6 @@ const WHITE = "\x1b[37;1m"; |
| 96 | const DIM = "\x1b[2m"; | 96 | const DIM = "\x1b[2m"; |
| 97 | const RESET = "\x1b[0m"; | 97 | const RESET = "\x1b[0m"; |
| 98 | 98 | ||
| 99 | pub var user_main_fn: ?fn() -> %void = null; | ||
| 100 | |||
| 101 | error PathNotFound; | 99 | error PathNotFound; |
| 102 | error InvalidDebugInfo; | 100 | error InvalidDebugInfo; |
| 103 | 101 | ||
| ... | @@ -113,6 +111,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty | ... | @@ -113,6 +111,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty |
| 113 | .debug_abbrev = undefined, | 111 | .debug_abbrev = undefined, |
| 114 | .debug_str = undefined, | 112 | .debug_str = undefined, |
| 115 | .debug_line = undefined, | 113 | .debug_line = undefined, |
| 114 | .debug_ranges = null, | ||
| 116 | .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), | 115 | .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), |
| 117 | .compile_unit_list = ArrayList(CompileUnit).init(allocator), | 116 | .compile_unit_list = ArrayList(CompileUnit).init(allocator), |
| 118 | }; | 117 | }; |
| ... | @@ -127,6 +126,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty | ... | @@ -127,6 +126,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty |
| 127 | st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo; | 126 | st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo; |
| 128 | st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo; | 127 | st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo; |
| 129 | st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo; | 128 | st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo; |
| 129 | st.debug_ranges = (%return st.elf.findSection(".debug_ranges")); | ||
| 130 | %return scanAllCompileUnits(st); | 130 | %return scanAllCompileUnits(st); |
| 131 | 131 | ||
| 132 | var ignored_count: usize = 0; | 132 | var ignored_count: usize = 0; |
| ... | @@ -144,7 +144,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty | ... | @@ -144,7 +144,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty |
| 144 | // at compile time. I'll call it issue #313 | 144 | // at compile time. I'll call it issue #313 |
| 145 | const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}"; | 145 | const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}"; |
| 146 | 146 | ||
| 147 | const compile_unit = findCompileUnit(st, return_address) ?? { | 147 | const compile_unit = findCompileUnit(st, return_address) %% { |
| 148 | %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n", | 148 | %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n", |
| 149 | return_address); | 149 | return_address); |
| 150 | continue; | 150 | continue; |
| ... | @@ -175,7 +175,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty | ... | @@ -175,7 +175,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty |
| 175 | return_address, compile_unit_name); | 175 | return_address, compile_unit_name); |
| 176 | }, | 176 | }, |
| 177 | else => return err, | 177 | else => return err, |
| 178 | }; | 178 | } |
| 179 | } | 179 | } |
| 180 | }, | 180 | }, |
| 181 | builtin.ObjectFormat.coff => { | 181 | builtin.ObjectFormat.coff => { |
| ... | @@ -233,6 +233,7 @@ const ElfStackTrace = struct { | ... | @@ -233,6 +233,7 @@ const ElfStackTrace = struct { |
| 233 | debug_abbrev: &elf.SectionHeader, | 233 | debug_abbrev: &elf.SectionHeader, |
| 234 | debug_str: &elf.SectionHeader, | 234 | debug_str: &elf.SectionHeader, |
| 235 | debug_line: &elf.SectionHeader, | 235 | debug_line: &elf.SectionHeader, |
| 236 | debug_ranges: ?&elf.SectionHeader, | ||
| 236 | abbrev_table_list: ArrayList(AbbrevTableHeader), | 237 | abbrev_table_list: ArrayList(AbbrevTableHeader), |
| 237 | compile_unit_list: ArrayList(CompileUnit), | 238 | compile_unit_list: ArrayList(CompileUnit), |
| 238 | 239 | ||
| ... | @@ -333,6 +334,15 @@ const Die = struct { | ... | @@ -333,6 +334,15 @@ const Die = struct { |
| 333 | }; | 334 | }; |
| 334 | } | 335 | } |
| 335 | 336 | ||
| 337 | fn getAttrSecOffset(self: &const Die, id: u64) -> %u64 { | ||
| 338 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; | ||
| 339 | return switch (*form_value) { | ||
| 340 | FormValue.Const => |value| value.asUnsignedLe(), | ||
| 341 | FormValue.SecOffset => |value| value, | ||
| 342 | else => error.InvalidDebugInfo, | ||
| 343 | }; | ||
| 344 | } | ||
| 345 | |||
| 336 | fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 { | 346 | fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 { |
| 337 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; | 347 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 338 | return switch (*form_value) { | 348 | return switch (*form_value) { |
| ... | @@ -347,7 +357,7 @@ const Die = struct { | ... | @@ -347,7 +357,7 @@ const Die = struct { |
| 347 | FormValue.String => |value| value, | 357 | FormValue.String => |value| value, |
| 348 | FormValue.StrPtr => |offset| getString(st, offset), | 358 | FormValue.StrPtr => |offset| getString(st, offset), |
| 349 | else => error.InvalidDebugInfo, | 359 | else => error.InvalidDebugInfo, |
| 350 | } | 360 | }; |
| 351 | } | 361 | } |
| 352 | }; | 362 | }; |
| 353 | 363 | ||
| ... | @@ -393,7 +403,7 @@ const LineNumberProgram = struct { | ... | @@ -393,7 +403,7 @@ const LineNumberProgram = struct { |
| 393 | pub fn init(is_stmt: bool, include_dirs: []const []const u8, | 403 | pub fn init(is_stmt: bool, include_dirs: []const []const u8, |
| 394 | file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram | 404 | file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram |
| 395 | { | 405 | { |
| 396 | LineNumberProgram { | 406 | return LineNumberProgram { |
| 397 | .address = 0, | 407 | .address = 0, |
| 398 | .file = 1, | 408 | .file = 1, |
| 399 | .line = 1, | 409 | .line = 1, |
| ... | @@ -411,7 +421,7 @@ const LineNumberProgram = struct { | ... | @@ -411,7 +421,7 @@ const LineNumberProgram = struct { |
| 411 | .prev_is_stmt = undefined, | 421 | .prev_is_stmt = undefined, |
| 412 | .prev_basic_block = undefined, | 422 | .prev_basic_block = undefined, |
| 413 | .prev_end_sequence = undefined, | 423 | .prev_end_sequence = undefined, |
| 414 | } | 424 | }; |
| 415 | } | 425 | } |
| 416 | 426 | ||
| 417 | pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo { | 427 | pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo { |
| ... | @@ -420,14 +430,11 @@ const LineNumberProgram = struct { | ... | @@ -420,14 +430,11 @@ const LineNumberProgram = struct { |
| 420 | return error.MissingDebugInfo; | 430 | return error.MissingDebugInfo; |
| 421 | } else if (self.prev_file - 1 >= self.file_entries.len) { | 431 | } else if (self.prev_file - 1 >= self.file_entries.len) { |
| 422 | return error.InvalidDebugInfo; | 432 | return error.InvalidDebugInfo; |
| 423 | } else { | 433 | } else &self.file_entries.items[self.prev_file - 1]; |
| 424 | &self.file_entries.items[self.prev_file - 1] | 434 | |
| 425 | }; | ||
| 426 | const dir_name = if (file_entry.dir_index >= self.include_dirs.len) { | 435 | const dir_name = if (file_entry.dir_index >= self.include_dirs.len) { |
| 427 | return error.InvalidDebugInfo; | 436 | return error.InvalidDebugInfo; |
| 428 | } else { | 437 | } else self.include_dirs[file_entry.dir_index]; |
| 429 | self.include_dirs[file_entry.dir_index] | ||
| 430 | }; | ||
| 431 | const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name); | 438 | const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name); |
| 432 | %defer self.file_entries.allocator.free(file_name); | 439 | %defer self.file_entries.allocator.free(file_name); |
| 433 | return LineInfo { | 440 | return LineInfo { |
| ... | @@ -484,28 +491,21 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: | ... | @@ -484,28 +491,21 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: |
| 484 | } | 491 | } |
| 485 | 492 | ||
| 486 | fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue { | 493 | fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue { |
| 487 | FormValue { .Const = Constant { | 494 | return FormValue { .Const = Constant { |
| 488 | .signed = signed, | 495 | .signed = signed, |
| 489 | .payload = %return readAllocBytes(allocator, in_stream, size), | 496 | .payload = %return readAllocBytes(allocator, in_stream, size), |
| 490 | }} | 497 | }}; |
| 491 | } | 498 | } |
| 492 | 499 | ||
| 493 | fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 { | 500 | fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 { |
| 494 | return if (is_64) { | 501 | return if (is_64) %return in_stream.readIntLe(u64) |
| 495 | %return in_stream.readIntLe(u64) | 502 | else u64(%return in_stream.readIntLe(u32)) ; |
| 496 | } else { | ||
| 497 | u64(%return in_stream.readIntLe(u32)) | ||
| 498 | }; | ||
| 499 | } | 503 | } |
| 500 | 504 | ||
| 501 | fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 { | 505 | fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 { |
| 502 | return if (@sizeOf(usize) == 4) { | 506 | return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32)) |
| 503 | u64(%return in_stream.readIntLe(u32)) | 507 | else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64) |
| 504 | } else if (@sizeOf(usize) == 8) { | 508 | else unreachable; |
| 505 | %return in_stream.readIntLe(u64) | ||
| 506 | } else { | ||
| 507 | unreachable; | ||
| 508 | }; | ||
| 509 | } | 509 | } |
| 510 | 510 | ||
| 511 | fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue { | 511 | fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue { |
| ... | @@ -524,9 +524,9 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u | ... | @@ -524,9 +524,9 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u |
| 524 | DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), | 524 | DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), |
| 525 | DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2), | 525 | DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2), |
| 526 | DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4), | 526 | DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4), |
| 527 | DW.FORM_block => { | 527 | DW.FORM_block => x: { |
| 528 | const block_len = %return readULeb128(in_stream); | 528 | const block_len = %return readULeb128(in_stream); |
| 529 | parseFormValueBlockLen(allocator, in_stream, block_len) | 529 | return parseFormValueBlockLen(allocator, in_stream, block_len); |
| 530 | }, | 530 | }, |
| 531 | DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1), | 531 | DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1), |
| 532 | DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2), | 532 | DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2), |
| ... | @@ -535,7 +535,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u | ... | @@ -535,7 +535,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u |
| 535 | DW.FORM_udata, DW.FORM_sdata => { | 535 | DW.FORM_udata, DW.FORM_sdata => { |
| 536 | const block_len = %return readULeb128(in_stream); | 536 | const block_len = %return readULeb128(in_stream); |
| 537 | const signed = form_id == DW.FORM_sdata; | 537 | const signed = form_id == DW.FORM_sdata; |
| 538 | parseFormValueConstant(allocator, in_stream, signed, block_len) | 538 | return parseFormValueConstant(allocator, in_stream, signed, block_len); |
| 539 | }, | 539 | }, |
| 540 | DW.FORM_exprloc => { | 540 | DW.FORM_exprloc => { |
| 541 | const size = %return readULeb128(in_stream); | 541 | const size = %return readULeb128(in_stream); |
| ... | @@ -552,7 +552,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u | ... | @@ -552,7 +552,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u |
| 552 | DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64), | 552 | DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64), |
| 553 | DW.FORM_ref_udata => { | 553 | DW.FORM_ref_udata => { |
| 554 | const ref_len = %return readULeb128(in_stream); | 554 | const ref_len = %return readULeb128(in_stream); |
| 555 | parseFormValueRefLen(allocator, in_stream, ref_len) | 555 | return parseFormValueRefLen(allocator, in_stream, ref_len); |
| 556 | }, | 556 | }, |
| 557 | 557 | ||
| 558 | DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, | 558 | DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, |
| ... | @@ -562,10 +562,10 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u | ... | @@ -562,10 +562,10 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u |
| 562 | DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, | 562 | DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, |
| 563 | DW.FORM_indirect => { | 563 | DW.FORM_indirect => { |
| 564 | const child_form_id = %return readULeb128(in_stream); | 564 | const child_form_id = %return readULeb128(in_stream); |
| 565 | parseFormValue(allocator, in_stream, child_form_id, is_64) | 565 | return parseFormValue(allocator, in_stream, child_form_id, is_64); |
| 566 | }, | 566 | }, |
| 567 | else => error.InvalidDebugInfo, | 567 | else => error.InvalidDebugInfo, |
| 568 | } | 568 | }; |
| 569 | } | 569 | } |
| 570 | 570 | ||
| 571 | fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable { | 571 | fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable { |
| ... | @@ -842,11 +842,9 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { | ... | @@ -842,11 +842,9 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { |
| 842 | const version = %return in_stream.readInt(st.elf.endian, u16); | 842 | const version = %return in_stream.readInt(st.elf.endian, u16); |
| 843 | if (version < 2 or version > 5) return error.InvalidDebugInfo; | 843 | if (version < 2 or version > 5) return error.InvalidDebugInfo; |
| 844 | 844 | ||
| 845 | const debug_abbrev_offset = if (is_64) { | 845 | const debug_abbrev_offset = |
| 846 | %return in_stream.readInt(st.elf.endian, u64) | 846 | if (is_64) %return in_stream.readInt(st.elf.endian, u64) |
| 847 | } else { | 847 | else %return in_stream.readInt(st.elf.endian, u32); |
| 848 | %return in_stream.readInt(st.elf.endian, u32) | ||
| 849 | }; | ||
| 850 | 848 | ||
| 851 | const address_size = %return in_stream.readByte(); | 849 | const address_size = %return in_stream.readByte(); |
| 852 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; | 850 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; |
| ... | @@ -862,28 +860,28 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { | ... | @@ -862,28 +860,28 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { |
| 862 | if (compile_unit_die.tag_id != DW.TAG_compile_unit) | 860 | if (compile_unit_die.tag_id != DW.TAG_compile_unit) |
| 863 | return error.InvalidDebugInfo; | 861 | return error.InvalidDebugInfo; |
| 864 | 862 | ||
| 865 | const pc_range = { | 863 | const pc_range = x: { |
| 866 | if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| { | 864 | if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| { |
| 867 | if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| { | 865 | if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| { |
| 868 | const pc_end = switch (*high_pc_value) { | 866 | const pc_end = switch (*high_pc_value) { |
| 869 | FormValue.Address => |value| value, | 867 | FormValue.Address => |value| value, |
| 870 | FormValue.Const => |value| { | 868 | FormValue.Const => |value| b: { |
| 871 | const offset = %return value.asUnsignedLe(); | 869 | const offset = %return value.asUnsignedLe(); |
| 872 | low_pc + offset | 870 | break :b (low_pc + offset); |
| 873 | }, | 871 | }, |
| 874 | else => return error.InvalidDebugInfo, | 872 | else => return error.InvalidDebugInfo, |
| 875 | }; | 873 | }; |
| 876 | PcRange { | 874 | break :x PcRange { |
| 877 | .start = low_pc, | 875 | .start = low_pc, |
| 878 | .end = pc_end, | 876 | .end = pc_end, |
| 879 | } | 877 | }; |
| 880 | } else { | 878 | } else { |
| 881 | null | 879 | break :x null; |
| 882 | } | 880 | } |
| 883 | } else |err| { | 881 | } else |err| { |
| 884 | if (err != error.MissingDebugInfo) | 882 | if (err != error.MissingDebugInfo) |
| 885 | return err; | 883 | return err; |
| 886 | null | 884 | break :x null; |
| 887 | } | 885 | } |
| 888 | }; | 886 | }; |
| 889 | 887 | ||
| ... | @@ -900,25 +898,51 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { | ... | @@ -900,25 +898,51 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { |
| 900 | } | 898 | } |
| 901 | } | 899 | } |
| 902 | 900 | ||
| 903 | fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> ?&const CompileUnit { | 901 | fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUnit { |
| 902 | var in_file_stream = io.FileInStream.init(&st.self_exe_file); | ||
| 903 | const in_stream = &in_file_stream.stream; | ||
| 904 | for (st.compile_unit_list.toSlice()) |*compile_unit| { | 904 | for (st.compile_unit_list.toSlice()) |*compile_unit| { |
| 905 | if (compile_unit.pc_range) |range| { | 905 | if (compile_unit.pc_range) |range| { |
| 906 | if (target_address >= range.start and target_address < range.end) | 906 | if (target_address >= range.start and target_address < range.end) |
| 907 | return compile_unit; | 907 | return compile_unit; |
| 908 | } | 908 | } |
| 909 | if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| { | ||
| 910 | var base_address: usize = 0; | ||
| 911 | if (st.debug_ranges) |debug_ranges| { | ||
| 912 | %return st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset); | ||
| 913 | while (true) { | ||
| 914 | const begin_addr = %return in_stream.readIntLe(usize); | ||
| 915 | const end_addr = %return in_stream.readIntLe(usize); | ||
| 916 | if (begin_addr == 0 and end_addr == 0) { | ||
| 917 | break; | ||
| 918 | } | ||
| 919 | if (begin_addr == @maxValue(usize)) { | ||
| 920 | base_address = begin_addr; | ||
| 921 | continue; | ||
| 922 | } | ||
| 923 | if (target_address >= begin_addr and target_address < end_addr) { | ||
| 924 | return compile_unit; | ||
| 925 | } | ||
| 926 | } | ||
| 927 | } | ||
| 928 | } else |err| { | ||
| 929 | if (err != error.MissingDebugInfo) | ||
| 930 | return err; | ||
| 931 | continue; | ||
| 932 | } | ||
| 909 | } | 933 | } |
| 910 | return null; | 934 | return error.MissingDebugInfo; |
| 911 | } | 935 | } |
| 912 | 936 | ||
| 913 | fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 { | 937 | fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 { |
| 914 | const first_32_bits = %return in_stream.readIntLe(u32); | 938 | const first_32_bits = %return in_stream.readIntLe(u32); |
| 915 | *is_64 = (first_32_bits == 0xffffffff); | 939 | *is_64 = (first_32_bits == 0xffffffff); |
| 916 | return if (*is_64) { | 940 | if (*is_64) { |
| 917 | %return in_stream.readIntLe(u64) | 941 | return in_stream.readIntLe(u64); |
| 918 | } else { | 942 | } else { |
| 919 | if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; | 943 | if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; |
| 920 | u64(first_32_bits) | 944 | return u64(first_32_bits); |
| 921 | }; | 945 | } |
| 922 | } | 946 | } |
| 923 | 947 | ||
| 924 | fn readULeb128(in_stream: &io.InStream) -> %u64 { | 948 | fn readULeb128(in_stream: &io.InStream) -> %u64 { |
| ... | @@ -965,40 +989,62 @@ fn readILeb128(in_stream: &io.InStream) -> %i64 { | ... | @@ -965,40 +989,62 @@ fn readILeb128(in_stream: &io.InStream) -> %i64 { |
| 965 | } | 989 | } |
| 966 | } | 990 | } |
| 967 | 991 | ||
| 968 | pub const global_allocator = &global_allocator_state; | 992 | pub const global_allocator = &global_fixed_allocator.allocator; |
| 969 | var global_allocator_state = mem.Allocator { | 993 | var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]); |
| 970 | .allocFn = globalAlloc, | 994 | var global_allocator_mem: [100 * 1024]u8 = undefined; |
| 971 | .reallocFn = globalRealloc, | ||
| 972 | .freeFn = globalFree, | ||
| 973 | }; | ||
| 974 | 995 | ||
| 975 | var some_mem: [100 * 1024]u8 = undefined; | 996 | /// Allocator that fails after N allocations, useful for making sure out of |
| 976 | var some_mem_index: usize = 0; | 997 | /// memory conditions are handled correctly. |
| 977 | 998 | pub const FailingAllocator = struct { | |
| 978 | error OutOfMemory; | 999 | allocator: mem.Allocator, |
| 1000 | index: usize, | ||
| 1001 | fail_index: usize, | ||
| 1002 | internal_allocator: &mem.Allocator, | ||
| 1003 | allocated_bytes: usize, | ||
| 1004 | |||
| 1005 | pub fn init(allocator: &mem.Allocator, fail_index: usize) -> FailingAllocator { | ||
| 1006 | return FailingAllocator { | ||
| 1007 | .internal_allocator = allocator, | ||
| 1008 | .fail_index = fail_index, | ||
| 1009 | .index = 0, | ||
| 1010 | .allocated_bytes = 0, | ||
| 1011 | .allocator = mem.Allocator { | ||
| 1012 | .allocFn = alloc, | ||
| 1013 | .reallocFn = realloc, | ||
| 1014 | .freeFn = free, | ||
| 1015 | }, | ||
| 1016 | }; | ||
| 1017 | } | ||
| 979 | 1018 | ||
| 980 | fn globalAlloc(self: &mem.Allocator, n: usize, alignment: usize) -> %[]u8 { | 1019 | fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 { |
| 981 | const addr = @ptrToInt(&some_mem[some_mem_index]); | 1020 | const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); |
| 982 | const rem = @rem(addr, alignment); | 1021 | if (self.index == self.fail_index) { |
| 983 | const march_forward_bytes = if (rem == 0) 0 else (alignment - rem); | 1022 | return error.OutOfMemory; |
| 984 | const adjusted_index = some_mem_index + march_forward_bytes; | 1023 | } |
| 985 | const end_index = adjusted_index + n; | 1024 | self.index += 1; |
| 986 | if (end_index > some_mem.len) { | 1025 | const result = %return self.internal_allocator.allocFn(self.internal_allocator, n, alignment); |
| 987 | return error.OutOfMemory; | 1026 | self.allocated_bytes += result.len; |
| 1027 | return result; | ||
| 988 | } | 1028 | } |
| 989 | const result = some_mem[adjusted_index .. end_index]; | ||
| 990 | some_mem_index = end_index; | ||
| 991 | return result; | ||
| 992 | } | ||
| 993 | 1029 | ||
| 994 | fn globalRealloc(self: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 { | 1030 | fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 { |
| 995 | if (new_size <= old_mem.len) { | 1031 | const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); |
| 996 | return old_mem[0..new_size]; | 1032 | if (new_size <= old_mem.len) { |
| 997 | } else { | 1033 | self.allocated_bytes -= old_mem.len - new_size; |
| 998 | const result = %return globalAlloc(self, new_size, alignment); | 1034 | return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment); |
| 999 | @memcpy(result.ptr, old_mem.ptr, old_mem.len); | 1035 | } |
| 1036 | if (self.index == self.fail_index) { | ||
| 1037 | return error.OutOfMemory; | ||
| 1038 | } | ||
| 1039 | self.index += 1; | ||
| 1040 | const result = %return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment); | ||
| 1041 | self.allocated_bytes += new_size - old_mem.len; | ||
| 1000 | return result; | 1042 | return result; |
| 1001 | } | 1043 | } |
| 1002 | } | ||
| 1003 | 1044 | ||
| 1004 | fn globalFree(self: &mem.Allocator, memory: []u8) { } | 1045 | fn free(allocator: &mem.Allocator, bytes: []u8) { |
| 1046 | const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); | ||
| 1047 | self.allocated_bytes -= bytes.len; | ||
| 1048 | return self.internal_allocator.freeFn(self.internal_allocator, bytes); | ||
| 1049 | } | ||
| 1050 | }; |
std/elf.zig+32-34| ... | @@ -188,39 +188,39 @@ pub const Elf = struct { | ... | @@ -188,39 +188,39 @@ pub const Elf = struct { |
| 188 | if (elf.is_64) { | 188 | if (elf.is_64) { |
| 189 | if (sh_entry_size != 64) return error.InvalidFormat; | 189 | if (sh_entry_size != 64) return error.InvalidFormat; |
| 190 | 190 | ||
| 191 | for (elf.section_headers) |*section| { | 191 | for (elf.section_headers) |*elf_section| { |
| 192 | section.name = %return in.readInt(elf.endian, u32); | 192 | elf_section.name = %return in.readInt(elf.endian, u32); |
| 193 | section.sh_type = %return in.readInt(elf.endian, u32); | 193 | elf_section.sh_type = %return in.readInt(elf.endian, u32); |
| 194 | section.flags = %return in.readInt(elf.endian, u64); | 194 | elf_section.flags = %return in.readInt(elf.endian, u64); |
| 195 | section.addr = %return in.readInt(elf.endian, u64); | 195 | elf_section.addr = %return in.readInt(elf.endian, u64); |
| 196 | section.offset = %return in.readInt(elf.endian, u64); | 196 | elf_section.offset = %return in.readInt(elf.endian, u64); |
| 197 | section.size = %return in.readInt(elf.endian, u64); | 197 | elf_section.size = %return in.readInt(elf.endian, u64); |
| 198 | section.link = %return in.readInt(elf.endian, u32); | 198 | elf_section.link = %return in.readInt(elf.endian, u32); |
| 199 | section.info = %return in.readInt(elf.endian, u32); | 199 | elf_section.info = %return in.readInt(elf.endian, u32); |
| 200 | section.addr_align = %return in.readInt(elf.endian, u64); | 200 | elf_section.addr_align = %return in.readInt(elf.endian, u64); |
| 201 | section.ent_size = %return in.readInt(elf.endian, u64); | 201 | elf_section.ent_size = %return in.readInt(elf.endian, u64); |
| 202 | } | 202 | } |
| 203 | } else { | 203 | } else { |
| 204 | if (sh_entry_size != 40) return error.InvalidFormat; | 204 | if (sh_entry_size != 40) return error.InvalidFormat; |
| 205 | 205 | ||
| 206 | for (elf.section_headers) |*section| { | 206 | for (elf.section_headers) |*elf_section| { |
| 207 | // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ? | 207 | // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ? |
| 208 | section.name = %return in.readInt(elf.endian, u32); | 208 | elf_section.name = %return in.readInt(elf.endian, u32); |
| 209 | section.sh_type = %return in.readInt(elf.endian, u32); | 209 | elf_section.sh_type = %return in.readInt(elf.endian, u32); |
| 210 | section.flags = u64(%return in.readInt(elf.endian, u32)); | 210 | elf_section.flags = u64(%return in.readInt(elf.endian, u32)); |
| 211 | section.addr = u64(%return in.readInt(elf.endian, u32)); | 211 | elf_section.addr = u64(%return in.readInt(elf.endian, u32)); |
| 212 | section.offset = u64(%return in.readInt(elf.endian, u32)); | 212 | elf_section.offset = u64(%return in.readInt(elf.endian, u32)); |
| 213 | section.size = u64(%return in.readInt(elf.endian, u32)); | 213 | elf_section.size = u64(%return in.readInt(elf.endian, u32)); |
| 214 | section.link = %return in.readInt(elf.endian, u32); | 214 | elf_section.link = %return in.readInt(elf.endian, u32); |
| 215 | section.info = %return in.readInt(elf.endian, u32); | 215 | elf_section.info = %return in.readInt(elf.endian, u32); |
| 216 | section.addr_align = u64(%return in.readInt(elf.endian, u32)); | 216 | elf_section.addr_align = u64(%return in.readInt(elf.endian, u32)); |
| 217 | section.ent_size = u64(%return in.readInt(elf.endian, u32)); | 217 | elf_section.ent_size = u64(%return in.readInt(elf.endian, u32)); |
| 218 | } | 218 | } |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | for (elf.section_headers) |*section| { | 221 | for (elf.section_headers) |*elf_section| { |
| 222 | if (section.sh_type != SHT_NOBITS) { | 222 | if (elf_section.sh_type != SHT_NOBITS) { |
| 223 | const file_end_offset = %return math.add(u64, section.offset, section.size); | 223 | const file_end_offset = %return math.add(u64, elf_section.offset, elf_section.size); |
| 224 | if (stream_end < file_end_offset) return error.InvalidFormat; | 224 | if (stream_end < file_end_offset) return error.InvalidFormat; |
| 225 | } | 225 | } |
| 226 | } | 226 | } |
| ... | @@ -243,29 +243,27 @@ pub const Elf = struct { | ... | @@ -243,29 +243,27 @@ pub const Elf = struct { |
| 243 | var file_stream = io.FileInStream.init(elf.in_file); | 243 | var file_stream = io.FileInStream.init(elf.in_file); |
| 244 | const in = &file_stream.stream; | 244 | const in = &file_stream.stream; |
| 245 | 245 | ||
| 246 | for (elf.section_headers) |*section| { | 246 | section_loop: for (elf.section_headers) |*elf_section| { |
| 247 | if (section.sh_type == SHT_NULL) continue; | 247 | if (elf_section.sh_type == SHT_NULL) continue; |
| 248 | 248 | ||
| 249 | const name_offset = elf.string_section.offset + section.name; | 249 | const name_offset = elf.string_section.offset + elf_section.name; |
| 250 | %return elf.in_file.seekTo(name_offset); | 250 | %return elf.in_file.seekTo(name_offset); |
| 251 | 251 | ||
| 252 | for (name) |expected_c| { | 252 | for (name) |expected_c| { |
| 253 | const target_c = %return in.readByte(); | 253 | const target_c = %return in.readByte(); |
| 254 | if (target_c == 0 or expected_c != target_c) goto next_section; | 254 | if (target_c == 0 or expected_c != target_c) continue :section_loop; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | { | 257 | { |
| 258 | const null_byte = %return in.readByte(); | 258 | const null_byte = %return in.readByte(); |
| 259 | if (null_byte == 0) return section; | 259 | if (null_byte == 0) return elf_section; |
| 260 | } | 260 | } |
| 261 | |||
| 262 | next_section: | ||
| 263 | } | 261 | } |
| 264 | 262 | ||
| 265 | return null; | 263 | return null; |
| 266 | } | 264 | } |
| 267 | 265 | ||
| 268 | pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void { | 266 | pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) -> %void { |
| 269 | %return elf.in_file.seekTo(section.offset); | 267 | %return elf.in_file.seekTo(elf_section.offset); |
| 270 | } | 268 | } |
| 271 | }; | 269 | }; |
std/endian.zig+3-3| ... | @@ -2,15 +2,15 @@ const mem = @import("mem.zig"); | ... | @@ -2,15 +2,15 @@ const mem = @import("mem.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | pub fn swapIfLe(comptime T: type, x: T) -> T { | 4 | pub fn swapIfLe(comptime T: type, x: T) -> T { |
| 5 | swapIf(false, T, x) | 5 | return swapIf(false, T, x); |
| 6 | } | 6 | } |
| 7 | 7 | ||
| 8 | pub fn swapIfBe(comptime T: type, x: T) -> T { | 8 | pub fn swapIfBe(comptime T: type, x: T) -> T { |
| 9 | swapIf(true, T, x) | 9 | return swapIf(true, T, x); |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T { | 12 | pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T { |
| 13 | if (builtin.endian == endian) swap(T, x) else x | 13 | return if (builtin.endian == endian) swap(T, x) else x; |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | pub fn swap(comptime T: type, x: T) -> T { | 16 | pub fn swap(comptime T: type, x: T) -> T { |
std/fmt/errol/enum3.zig+2-2| ... | @@ -439,10 +439,10 @@ const Slab = struct { | ... | @@ -439,10 +439,10 @@ const Slab = struct { |
| 439 | }; | 439 | }; |
| 440 | 440 | ||
| 441 | fn slab(str: []const u8, exp: i32) -> Slab { | 441 | fn slab(str: []const u8, exp: i32) -> Slab { |
| 442 | Slab { | 442 | return Slab { |
| 443 | .str = str, | 443 | .str = str, |
| 444 | .exp = exp, | 444 | .exp = exp, |
| 445 | } | 445 | }; |
| 446 | } | 446 | } |
| 447 | 447 | ||
| 448 | pub const enum3_data = []Slab { | 448 | pub const enum3_data = []Slab { |
std/fmt/index.zig+21-16| ... | @@ -251,11 +251,10 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons | ... | @@ -251,11 +251,10 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons |
| 251 | %return output(context, float_decimal.digits[0..1]); | 251 | %return output(context, float_decimal.digits[0..1]); |
| 252 | %return output(context, "."); | 252 | %return output(context, "."); |
| 253 | if (float_decimal.digits.len > 1) { | 253 | if (float_decimal.digits.len > 1) { |
| 254 | const num_digits = if (@typeOf(value) == f32) { | 254 | const num_digits = if (@typeOf(value) == f32) |
| 255 | math.min(usize(9), float_decimal.digits.len) | 255 | math.min(usize(9), float_decimal.digits.len) |
| 256 | } else { | 256 | else |
| 257 | float_decimal.digits.len | 257 | float_decimal.digits.len; |
| 258 | }; | ||
| 259 | %return output(context, float_decimal.digits[1 .. num_digits]); | 258 | %return output(context, float_decimal.digits[1 .. num_digits]); |
| 260 | } else { | 259 | } else { |
| 261 | %return output(context, "0"); | 260 | %return output(context, "0"); |
| ... | @@ -372,6 +371,10 @@ test "fmt.parseInt" { | ... | @@ -372,6 +371,10 @@ test "fmt.parseInt" { |
| 372 | assert(%%parseInt(i32, "-10", 10) == -10); | 371 | assert(%%parseInt(i32, "-10", 10) == -10); |
| 373 | assert(%%parseInt(i32, "+10", 10) == 10); | 372 | assert(%%parseInt(i32, "+10", 10) == 10); |
| 374 | assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidChar); | 373 | assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidChar); |
| 374 | assert(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidChar); | ||
| 375 | assert(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidChar); | ||
| 376 | assert(%%parseInt(u8, "255", 10) == 255); | ||
| 377 | assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow); | ||
| 375 | } | 378 | } |
| 376 | 379 | ||
| 377 | pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) -> %T { | 380 | pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) -> %T { |
| ... | @@ -413,14 +416,16 @@ const BufPrintContext = struct { | ... | @@ -413,14 +416,16 @@ const BufPrintContext = struct { |
| 413 | remaining: []u8, | 416 | remaining: []u8, |
| 414 | }; | 417 | }; |
| 415 | 418 | ||
| 419 | error BufferTooSmall; | ||
| 416 | fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) -> %void { | 420 | fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) -> %void { |
| 421 | if (context.remaining.len < bytes.len) return error.BufferTooSmall; | ||
| 417 | mem.copy(u8, context.remaining, bytes); | 422 | mem.copy(u8, context.remaining, bytes); |
| 418 | context.remaining = context.remaining[bytes.len..]; | 423 | context.remaining = context.remaining[bytes.len..]; |
| 419 | } | 424 | } |
| 420 | 425 | ||
| 421 | pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) -> []u8 { | 426 | pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) -> %[]u8 { |
| 422 | var context = BufPrintContext { .remaining = buf, }; | 427 | var context = BufPrintContext { .remaining = buf, }; |
| 423 | %%format(&context, bufPrintWrite, fmt, args); | 428 | %return format(&context, bufPrintWrite, fmt, args); |
| 424 | return buf[0..buf.len - context.remaining.len]; | 429 | return buf[0..buf.len - context.remaining.len]; |
| 425 | } | 430 | } |
| 426 | 431 | ||
| ... | @@ -476,31 +481,31 @@ test "fmt.format" { | ... | @@ -476,31 +481,31 @@ test "fmt.format" { |
| 476 | { | 481 | { |
| 477 | var buf1: [32]u8 = undefined; | 482 | var buf1: [32]u8 = undefined; |
| 478 | const value: ?i32 = 1234; | 483 | const value: ?i32 = 1234; |
| 479 | const result = bufPrint(buf1[0..], "nullable: {}\n", value); | 484 | const result = %%bufPrint(buf1[0..], "nullable: {}\n", value); |
| 480 | assert(mem.eql(u8, result, "nullable: 1234\n")); | 485 | assert(mem.eql(u8, result, "nullable: 1234\n")); |
| 481 | } | 486 | } |
| 482 | { | 487 | { |
| 483 | var buf1: [32]u8 = undefined; | 488 | var buf1: [32]u8 = undefined; |
| 484 | const value: ?i32 = null; | 489 | const value: ?i32 = null; |
| 485 | const result = bufPrint(buf1[0..], "nullable: {}\n", value); | 490 | const result = %%bufPrint(buf1[0..], "nullable: {}\n", value); |
| 486 | assert(mem.eql(u8, result, "nullable: null\n")); | 491 | assert(mem.eql(u8, result, "nullable: null\n")); |
| 487 | } | 492 | } |
| 488 | { | 493 | { |
| 489 | var buf1: [32]u8 = undefined; | 494 | var buf1: [32]u8 = undefined; |
| 490 | const value: %i32 = 1234; | 495 | const value: %i32 = 1234; |
| 491 | const result = bufPrint(buf1[0..], "error union: {}\n", value); | 496 | const result = %%bufPrint(buf1[0..], "error union: {}\n", value); |
| 492 | assert(mem.eql(u8, result, "error union: 1234\n")); | 497 | assert(mem.eql(u8, result, "error union: 1234\n")); |
| 493 | } | 498 | } |
| 494 | { | 499 | { |
| 495 | var buf1: [32]u8 = undefined; | 500 | var buf1: [32]u8 = undefined; |
| 496 | const value: %i32 = error.InvalidChar; | 501 | const value: %i32 = error.InvalidChar; |
| 497 | const result = bufPrint(buf1[0..], "error union: {}\n", value); | 502 | const result = %%bufPrint(buf1[0..], "error union: {}\n", value); |
| 498 | assert(mem.eql(u8, result, "error union: error.InvalidChar\n")); | 503 | assert(mem.eql(u8, result, "error union: error.InvalidChar\n")); |
| 499 | } | 504 | } |
| 500 | { | 505 | { |
| 501 | var buf1: [32]u8 = undefined; | 506 | var buf1: [32]u8 = undefined; |
| 502 | const value: u3 = 0b101; | 507 | const value: u3 = 0b101; |
| 503 | const result = bufPrint(buf1[0..], "u3: {}\n", value); | 508 | const result = %%bufPrint(buf1[0..], "u3: {}\n", value); |
| 504 | assert(mem.eql(u8, result, "u3: 5\n")); | 509 | assert(mem.eql(u8, result, "u3: 5\n")); |
| 505 | } | 510 | } |
| 506 | 511 | ||
| ... | @@ -510,28 +515,28 @@ test "fmt.format" { | ... | @@ -510,28 +515,28 @@ test "fmt.format" { |
| 510 | { | 515 | { |
| 511 | var buf1: [32]u8 = undefined; | 516 | var buf1: [32]u8 = undefined; |
| 512 | const value: f32 = 12.34; | 517 | const value: f32 = 12.34; |
| 513 | const result = bufPrint(buf1[0..], "f32: {}\n", value); | 518 | const result = %%bufPrint(buf1[0..], "f32: {}\n", value); |
| 514 | assert(mem.eql(u8, result, "f32: 1.23400001e1\n")); | 519 | assert(mem.eql(u8, result, "f32: 1.23400001e1\n")); |
| 515 | } | 520 | } |
| 516 | { | 521 | { |
| 517 | var buf1: [32]u8 = undefined; | 522 | var buf1: [32]u8 = undefined; |
| 518 | const value: f64 = -12.34e10; | 523 | const value: f64 = -12.34e10; |
| 519 | const result = bufPrint(buf1[0..], "f64: {}\n", value); | 524 | const result = %%bufPrint(buf1[0..], "f64: {}\n", value); |
| 520 | assert(mem.eql(u8, result, "f64: -1.234e11\n")); | 525 | assert(mem.eql(u8, result, "f64: -1.234e11\n")); |
| 521 | } | 526 | } |
| 522 | { | 527 | { |
| 523 | var buf1: [32]u8 = undefined; | 528 | var buf1: [32]u8 = undefined; |
| 524 | const result = bufPrint(buf1[0..], "f64: {}\n", math.nan_f64); | 529 | const result = %%bufPrint(buf1[0..], "f64: {}\n", math.nan_f64); |
| 525 | assert(mem.eql(u8, result, "f64: NaN\n")); | 530 | assert(mem.eql(u8, result, "f64: NaN\n")); |
| 526 | } | 531 | } |
| 527 | { | 532 | { |
| 528 | var buf1: [32]u8 = undefined; | 533 | var buf1: [32]u8 = undefined; |
| 529 | const result = bufPrint(buf1[0..], "f64: {}\n", math.inf_f64); | 534 | const result = %%bufPrint(buf1[0..], "f64: {}\n", math.inf_f64); |
| 530 | assert(mem.eql(u8, result, "f64: Infinity\n")); | 535 | assert(mem.eql(u8, result, "f64: Infinity\n")); |
| 531 | } | 536 | } |
| 532 | { | 537 | { |
| 533 | var buf1: [32]u8 = undefined; | 538 | var buf1: [32]u8 = undefined; |
| 534 | const result = bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64); | 539 | const result = %%bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64); |
| 535 | assert(mem.eql(u8, result, "f64: -Infinity\n")); | 540 | assert(mem.eql(u8, result, "f64: -Infinity\n")); |
| 536 | } | 541 | } |
| 537 | } | 542 | } |
std/hash_map.zig+10-10| ... | @@ -12,7 +12,7 @@ pub fn HashMap(comptime K: type, comptime V: type, | ... | @@ -12,7 +12,7 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 12 | comptime hash: fn(key: K)->u32, | 12 | comptime hash: fn(key: K)->u32, |
| 13 | comptime eql: fn(a: K, b: K)->bool) -> type | 13 | comptime eql: fn(a: K, b: K)->bool) -> type |
| 14 | { | 14 | { |
| 15 | struct { | 15 | return struct { |
| 16 | entries: []Entry, | 16 | entries: []Entry, |
| 17 | size: usize, | 17 | size: usize, |
| 18 | max_distance_from_start_index: usize, | 18 | max_distance_from_start_index: usize, |
| ... | @@ -51,19 +51,19 @@ pub fn HashMap(comptime K: type, comptime V: type, | ... | @@ -51,19 +51,19 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 51 | return entry; | 51 | return entry; |
| 52 | } | 52 | } |
| 53 | } | 53 | } |
| 54 | unreachable // no next item | 54 | unreachable; // no next item |
| 55 | } | 55 | } |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | pub fn init(allocator: &Allocator) -> Self { | 58 | pub fn init(allocator: &Allocator) -> Self { |
| 59 | Self { | 59 | return Self { |
| 60 | .entries = []Entry{}, | 60 | .entries = []Entry{}, |
| 61 | .allocator = allocator, | 61 | .allocator = allocator, |
| 62 | .size = 0, | 62 | .size = 0, |
| 63 | .max_distance_from_start_index = 0, | 63 | .max_distance_from_start_index = 0, |
| 64 | // it doesn't actually matter what we set this to since we use wrapping integer arithmetic | 64 | // it doesn't actually matter what we set this to since we use wrapping integer arithmetic |
| 65 | .modification_count = undefined, | 65 | .modification_count = undefined, |
| 66 | } | 66 | }; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | pub fn deinit(hm: &Self) { | 69 | pub fn deinit(hm: &Self) { |
| ... | @@ -133,7 +133,7 @@ pub fn HashMap(comptime K: type, comptime V: type, | ... | @@ -133,7 +133,7 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 133 | entry.distance_from_start_index -= 1; | 133 | entry.distance_from_start_index -= 1; |
| 134 | entry = next_entry; | 134 | entry = next_entry; |
| 135 | } | 135 | } |
| 136 | unreachable // shifting everything in the table | 136 | unreachable; // shifting everything in the table |
| 137 | }} | 137 | }} |
| 138 | return null; | 138 | return null; |
| 139 | } | 139 | } |
| ... | @@ -169,7 +169,7 @@ pub fn HashMap(comptime K: type, comptime V: type, | ... | @@ -169,7 +169,7 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 169 | const start_index = hm.keyToIndex(key); | 169 | const start_index = hm.keyToIndex(key); |
| 170 | var roll_over: usize = 0; | 170 | var roll_over: usize = 0; |
| 171 | var distance_from_start_index: usize = 0; | 171 | var distance_from_start_index: usize = 0; |
| 172 | while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1}) { | 172 | while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1;}) { |
| 173 | const index = (start_index + roll_over) % hm.entries.len; | 173 | const index = (start_index + roll_over) % hm.entries.len; |
| 174 | const entry = &hm.entries[index]; | 174 | const entry = &hm.entries[index]; |
| 175 | 175 | ||
| ... | @@ -210,7 +210,7 @@ pub fn HashMap(comptime K: type, comptime V: type, | ... | @@ -210,7 +210,7 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 210 | }; | 210 | }; |
| 211 | return result; | 211 | return result; |
| 212 | } | 212 | } |
| 213 | unreachable // put into a full map | 213 | unreachable; // put into a full map |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | fn internalGet(hm: &Self, key: K) -> ?&Entry { | 216 | fn internalGet(hm: &Self, key: K) -> ?&Entry { |
| ... | @@ -228,7 +228,7 @@ pub fn HashMap(comptime K: type, comptime V: type, | ... | @@ -228,7 +228,7 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 228 | fn keyToIndex(hm: &Self, key: K) -> usize { | 228 | fn keyToIndex(hm: &Self, key: K) -> usize { |
| 229 | return usize(hash(key)) % hm.entries.len; | 229 | return usize(hash(key)) % hm.entries.len; |
| 230 | } | 230 | } |
| 231 | } | 231 | }; |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | test "basicHashMapTest" { | 234 | test "basicHashMapTest" { |
| ... | @@ -251,9 +251,9 @@ test "basicHashMapTest" { | ... | @@ -251,9 +251,9 @@ test "basicHashMapTest" { |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | fn hash_i32(x: i32) -> u32 { | 253 | fn hash_i32(x: i32) -> u32 { |
| 254 | @bitCast(u32, x) | 254 | return @bitCast(u32, x); |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | fn eql_i32(a: i32, b: i32) -> bool { | 257 | fn eql_i32(a: i32, b: i32) -> bool { |
| 258 | a == b | 258 | return a == b; |
| 259 | } | 259 | } |
std/heap.zig+15-17| ... | @@ -10,30 +10,28 @@ const Allocator = mem.Allocator; | ... | @@ -10,30 +10,28 @@ const Allocator = mem.Allocator; |
| 10 | 10 | ||
| 11 | error OutOfMemory; | 11 | error OutOfMemory; |
| 12 | 12 | ||
| 13 | pub var c_allocator = Allocator { | 13 | pub const c_allocator = &c_allocator_state; |
| 14 | var c_allocator_state = Allocator { | ||
| 14 | .allocFn = cAlloc, | 15 | .allocFn = cAlloc, |
| 15 | .reallocFn = cRealloc, | 16 | .reallocFn = cRealloc, |
| 16 | .freeFn = cFree, | 17 | .freeFn = cFree, |
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| 19 | fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 { | 20 | fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 { |
| 20 | if (c.malloc(usize(n))) |buf| { | 21 | return if (c.malloc(usize(n))) |buf| |
| 21 | @ptrCast(&u8, buf)[0..n] | 22 | @ptrCast(&u8, buf)[0..n] |
| 22 | } else { | 23 | else |
| 23 | error.OutOfMemory | 24 | error.OutOfMemory; |
| 24 | } | ||
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 { | 27 | fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 { |
| 28 | if (new_size <= old_mem.len) { | 28 | const old_ptr = @ptrCast(&c_void, old_mem.ptr); |
| 29 | old_mem[0..new_size] | 29 | if (c.realloc(old_ptr, new_size)) |buf| { |
| 30 | return @ptrCast(&u8, buf)[0..new_size]; | ||
| 31 | } else if (new_size <= old_mem.len) { | ||
| 32 | return old_mem[0..new_size]; | ||
| 30 | } else { | 33 | } else { |
| 31 | const old_ptr = @ptrCast(&c_void, old_mem.ptr); | 34 | return error.OutOfMemory; |
| 32 | if (c.realloc(old_ptr, usize(new_size))) |buf| { | ||
| 33 | @ptrCast(&u8, buf)[0..new_size] | ||
| 34 | } else { | ||
| 35 | error.OutOfMemory | ||
| 36 | } | ||
| 37 | } | 35 | } |
| 38 | } | 36 | } |
| 39 | 37 | ||
| ... | @@ -106,7 +104,7 @@ pub const IncrementingAllocator = struct { | ... | @@ -106,7 +104,7 @@ pub const IncrementingAllocator = struct { |
| 106 | return self.bytes.len - self.end_index; | 104 | return self.bytes.len - self.end_index; |
| 107 | } | 105 | } |
| 108 | 106 | ||
| 109 | fn alloc(allocator: &Allocator, n: usize, alignment: usize) -> %[]u8 { | 107 | fn alloc(allocator: &Allocator, n: usize, alignment: u29) -> %[]u8 { |
| 110 | const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); | 108 | const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); |
| 111 | const addr = @ptrToInt(&self.bytes[self.end_index]); | 109 | const addr = @ptrToInt(&self.bytes[self.end_index]); |
| 112 | const rem = @rem(addr, alignment); | 110 | const rem = @rem(addr, alignment); |
| ... | @@ -121,7 +119,7 @@ pub const IncrementingAllocator = struct { | ... | @@ -121,7 +119,7 @@ pub const IncrementingAllocator = struct { |
| 121 | return result; | 119 | return result; |
| 122 | } | 120 | } |
| 123 | 121 | ||
| 124 | fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 { | 122 | fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 { |
| 125 | if (new_size <= old_mem.len) { | 123 | if (new_size <= old_mem.len) { |
| 126 | return old_mem[0..new_size]; | 124 | return old_mem[0..new_size]; |
| 127 | } else { | 125 | } else { |
std/index.zig+8-6| ... | @@ -1,7 +1,9 @@ | ... | @@ -1,7 +1,9 @@ |
| 1 | pub const ArrayList = @import("array_list.zig").ArrayList; | 1 | pub const ArrayList = @import("array_list.zig").ArrayList; |
| 2 | pub const AlignedArrayList = @import("array_list.zig").AlignedArrayList; | ||
| 2 | pub const BufMap = @import("buf_map.zig").BufMap; | 3 | pub const BufMap = @import("buf_map.zig").BufMap; |
| 3 | pub const BufSet = @import("buf_set.zig").BufSet; | 4 | pub const BufSet = @import("buf_set.zig").BufSet; |
| 4 | pub const Buffer = @import("buffer.zig").Buffer; | 5 | pub const Buffer = @import("buffer.zig").Buffer; |
| 6 | pub const BufferOutStream = @import("buffer.zig").BufferOutStream; | ||
| 5 | pub const HashMap = @import("hash_map.zig").HashMap; | 7 | pub const HashMap = @import("hash_map.zig").HashMap; |
| 6 | pub const LinkedList = @import("linked_list.zig").LinkedList; | 8 | pub const LinkedList = @import("linked_list.zig").LinkedList; |
| 7 | 9 | ||
| ... | @@ -26,12 +28,12 @@ pub const sort = @import("sort.zig"); | ... | @@ -26,12 +28,12 @@ pub const sort = @import("sort.zig"); |
| 26 | 28 | ||
| 27 | test "std" { | 29 | test "std" { |
| 28 | // run tests from these | 30 | // run tests from these |
| 29 | _ = @import("array_list.zig").ArrayList; | 31 | _ = @import("array_list.zig"); |
| 30 | _ = @import("buf_map.zig").BufMap; | 32 | _ = @import("buf_map.zig"); |
| 31 | _ = @import("buf_set.zig").BufSet; | 33 | _ = @import("buf_set.zig"); |
| 32 | _ = @import("buffer.zig").Buffer; | 34 | _ = @import("buffer.zig"); |
| 33 | _ = @import("hash_map.zig").HashMap; | 35 | _ = @import("hash_map.zig"); |
| 34 | _ = @import("linked_list.zig").LinkedList; | 36 | _ = @import("linked_list.zig"); |
| 35 | 37 | ||
| 36 | _ = @import("base64.zig"); | 38 | _ = @import("base64.zig"); |
| 37 | _ = @import("build.zig"); | 39 | _ = @import("build.zig"); |
std/io.zig+56-16| ... | @@ -50,35 +50,32 @@ error Unseekable; | ... | @@ -50,35 +50,32 @@ error Unseekable; |
| 50 | error EndOfFile; | 50 | error EndOfFile; |
| 51 | 51 | ||
| 52 | pub fn getStdErr() -> %File { | 52 | pub fn getStdErr() -> %File { |
| 53 | const handle = if (is_windows) { | 53 | const handle = if (is_windows) |
| 54 | %return os.windowsGetStdHandle(system.STD_ERROR_HANDLE) | 54 | %return os.windowsGetStdHandle(system.STD_ERROR_HANDLE) |
| 55 | } else if (is_posix) { | 55 | else if (is_posix) |
| 56 | system.STDERR_FILENO | 56 | system.STDERR_FILENO |
| 57 | } else { | 57 | else |
| 58 | unreachable | 58 | unreachable; |
| 59 | }; | ||
| 60 | return File.openHandle(handle); | 59 | return File.openHandle(handle); |
| 61 | } | 60 | } |
| 62 | 61 | ||
| 63 | pub fn getStdOut() -> %File { | 62 | pub fn getStdOut() -> %File { |
| 64 | const handle = if (is_windows) { | 63 | const handle = if (is_windows) |
| 65 | %return os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE) | 64 | %return os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE) |
| 66 | } else if (is_posix) { | 65 | else if (is_posix) |
| 67 | system.STDOUT_FILENO | 66 | system.STDOUT_FILENO |
| 68 | } else { | 67 | else |
| 69 | unreachable | 68 | unreachable; |
| 70 | }; | ||
| 71 | return File.openHandle(handle); | 69 | return File.openHandle(handle); |
| 72 | } | 70 | } |
| 73 | 71 | ||
| 74 | pub fn getStdIn() -> %File { | 72 | pub fn getStdIn() -> %File { |
| 75 | const handle = if (is_windows) { | 73 | const handle = if (is_windows) |
| 76 | %return os.windowsGetStdHandle(system.STD_INPUT_HANDLE) | 74 | %return os.windowsGetStdHandle(system.STD_INPUT_HANDLE) |
| 77 | } else if (is_posix) { | 75 | else if (is_posix) |
| 78 | system.STDIN_FILENO | 76 | system.STDIN_FILENO |
| 79 | } else { | 77 | else |
| 80 | unreachable | 78 | unreachable; |
| 81 | }; | ||
| 82 | return File.openHandle(handle); | 79 | return File.openHandle(handle); |
| 83 | } | 80 | } |
| 84 | 81 | ||
| ... | @@ -261,7 +258,7 @@ pub const File = struct { | ... | @@ -261,7 +258,7 @@ pub const File = struct { |
| 261 | system.EBADF => error.BadFd, | 258 | system.EBADF => error.BadFd, |
| 262 | system.ENOMEM => error.SystemResources, | 259 | system.ENOMEM => error.SystemResources, |
| 263 | else => os.unexpectedErrorPosix(err), | 260 | else => os.unexpectedErrorPosix(err), |
| 264 | } | 261 | }; |
| 265 | } | 262 | } |
| 266 | 263 | ||
| 267 | return usize(stat.size); | 264 | return usize(stat.size); |
| ... | @@ -481,6 +478,14 @@ pub const OutStream = struct { | ... | @@ -481,6 +478,14 @@ pub const OutStream = struct { |
| 481 | const slice = (&byte)[0..1]; | 478 | const slice = (&byte)[0..1]; |
| 482 | return self.writeFn(self, slice); | 479 | return self.writeFn(self, slice); |
| 483 | } | 480 | } |
| 481 | |||
| 482 | pub fn writeByteNTimes(self: &OutStream, byte: u8, n: usize) -> %void { | ||
| 483 | const slice = (&byte)[0..1]; | ||
| 484 | var i: usize = 0; | ||
| 485 | while (i < n) : (i += 1) { | ||
| 486 | %return self.writeFn(self, slice); | ||
| 487 | } | ||
| 488 | } | ||
| 484 | }; | 489 | }; |
| 485 | 490 | ||
| 486 | /// `path` may need to be copied in memory to add a null terminating byte. In this case | 491 | /// `path` may need to be copied in memory to add a null terminating byte. In this case |
| ... | @@ -493,6 +498,20 @@ pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) | ... | @@ -493,6 +498,20 @@ pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) |
| 493 | %return file.write(data); | 498 | %return file.write(data); |
| 494 | } | 499 | } |
| 495 | 500 | ||
| 501 | /// On success, caller owns returned buffer. | ||
| 502 | pub fn readFileAlloc(path: []const u8, allocator: &mem.Allocator) -> %[]u8 { | ||
| 503 | var file = %return File.openRead(path, allocator); | ||
| 504 | defer file.close(); | ||
| 505 | |||
| 506 | const size = %return file.getEndPos(); | ||
| 507 | const buf = %return allocator.alloc(u8, size); | ||
| 508 | %defer allocator.free(buf); | ||
| 509 | |||
| 510 | var adapter = FileInStream.init(&file); | ||
| 511 | %return adapter.stream.readNoEof(buf); | ||
| 512 | return buf; | ||
| 513 | } | ||
| 514 | |||
| 496 | pub const BufferedInStream = BufferedInStreamCustom(os.page_size); | 515 | pub const BufferedInStream = BufferedInStreamCustom(os.page_size); |
| 497 | 516 | ||
| 498 | pub fn BufferedInStreamCustom(comptime buffer_size: usize) -> type { | 517 | pub fn BufferedInStreamCustom(comptime buffer_size: usize) -> type { |
| ... | @@ -619,3 +638,24 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) -> type { | ... | @@ -619,3 +638,24 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) -> type { |
| 619 | } | 638 | } |
| 620 | }; | 639 | }; |
| 621 | } | 640 | } |
| 641 | |||
| 642 | /// Implementation of OutStream trait for Buffer | ||
| 643 | pub const BufferOutStream = struct { | ||
| 644 | buffer: &Buffer, | ||
| 645 | stream: OutStream, | ||
| 646 | |||
| 647 | pub fn init(buffer: &Buffer) -> BufferOutStream { | ||
| 648 | return BufferOutStream { | ||
| 649 | .buffer = buffer, | ||
| 650 | .stream = OutStream { | ||
| 651 | .writeFn = writeFn, | ||
| 652 | }, | ||
| 653 | }; | ||
| 654 | } | ||
| 655 | |||
| 656 | fn writeFn(out_stream: &OutStream, bytes: []const u8) -> %void { | ||
| 657 | const self = @fieldParentPtr(BufferOutStream, "stream", out_stream); | ||
| 658 | return self.buffer.append(bytes); | ||
| 659 | } | ||
| 660 | }; | ||
| 661 |
std/linked_list.zig+7-7| ... | @@ -5,7 +5,7 @@ const Allocator = mem.Allocator; | ... | @@ -5,7 +5,7 @@ const Allocator = mem.Allocator; |
| 5 | 5 | ||
| 6 | /// Generic doubly linked list. | 6 | /// Generic doubly linked list. |
| 7 | pub fn LinkedList(comptime T: type) -> type { | 7 | pub fn LinkedList(comptime T: type) -> type { |
| 8 | struct { | 8 | return struct { |
| 9 | const Self = this; | 9 | const Self = this; |
| 10 | 10 | ||
| 11 | /// Node inside the linked list wrapping the actual data. | 11 | /// Node inside the linked list wrapping the actual data. |
| ... | @@ -15,11 +15,11 @@ pub fn LinkedList(comptime T: type) -> type { | ... | @@ -15,11 +15,11 @@ pub fn LinkedList(comptime T: type) -> type { |
| 15 | data: T, | 15 | data: T, |
| 16 | 16 | ||
| 17 | pub fn init(data: &const T) -> Node { | 17 | pub fn init(data: &const T) -> Node { |
| 18 | Node { | 18 | return Node { |
| 19 | .prev = null, | 19 | .prev = null, |
| 20 | .next = null, | 20 | .next = null, |
| 21 | .data = *data, | 21 | .data = *data, |
| 22 | } | 22 | }; |
| 23 | } | 23 | } |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| ... | @@ -32,11 +32,11 @@ pub fn LinkedList(comptime T: type) -> type { | ... | @@ -32,11 +32,11 @@ pub fn LinkedList(comptime T: type) -> type { |
| 32 | /// Returns: | 32 | /// Returns: |
| 33 | /// An empty linked list. | 33 | /// An empty linked list. |
| 34 | pub fn init() -> Self { | 34 | pub fn init() -> Self { |
| 35 | Self { | 35 | return Self { |
| 36 | .first = null, | 36 | .first = null, |
| 37 | .last = null, | 37 | .last = null, |
| 38 | .len = 0, | 38 | .len = 0, |
| 39 | } | 39 | }; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | /// Insert a new node after an existing one. | 42 | /// Insert a new node after an existing one. |
| ... | @@ -166,7 +166,7 @@ pub fn LinkedList(comptime T: type) -> type { | ... | @@ -166,7 +166,7 @@ pub fn LinkedList(comptime T: type) -> type { |
| 166 | /// Returns: | 166 | /// Returns: |
| 167 | /// A pointer to the new node. | 167 | /// A pointer to the new node. |
| 168 | pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node { | 168 | pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node { |
| 169 | allocator.create(Node) | 169 | return allocator.create(Node); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | /// Deallocate a node. | 172 | /// Deallocate a node. |
| ... | @@ -191,7 +191,7 @@ pub fn LinkedList(comptime T: type) -> type { | ... | @@ -191,7 +191,7 @@ pub fn LinkedList(comptime T: type) -> type { |
| 191 | *node = Node.init(data); | 191 | *node = Node.init(data); |
| 192 | return node; | 192 | return node; |
| 193 | } | 193 | } |
| 194 | } | 194 | }; |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | test "basic linked list test" { | 197 | test "basic linked list test" { |
std/math/acos.zig+8-8| ... | @@ -7,11 +7,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -7,11 +7,11 @@ const assert = @import("../debug.zig").assert; |
| 7 | 7 | ||
| 8 | pub fn acos(x: var) -> @typeOf(x) { | 8 | pub fn acos(x: var) -> @typeOf(x) { |
| 9 | const T = @typeOf(x); | 9 | const T = @typeOf(x); |
| 10 | switch (T) { | 10 | return switch (T) { |
| 11 | f32 => @inlineCall(acos32, x), | 11 | f32 => acos32(x), |
| 12 | f64 => @inlineCall(acos64, x), | 12 | f64 => acos64(x), |
| 13 | else => @compileError("acos not implemented for " ++ @typeName(T)), | 13 | else => @compileError("acos not implemented for " ++ @typeName(T)), |
| 14 | } | 14 | }; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | fn r32(z: f32) -> f32 { | 17 | fn r32(z: f32) -> f32 { |
| ... | @@ -22,7 +22,7 @@ fn r32(z: f32) -> f32 { | ... | @@ -22,7 +22,7 @@ fn r32(z: f32) -> f32 { |
| 22 | 22 | ||
| 23 | const p = z * (pS0 + z * (pS1 + z * pS2)); | 23 | const p = z * (pS0 + z * (pS1 + z * pS2)); |
| 24 | const q = 1.0 + z * qS1; | 24 | const q = 1.0 + z * qS1; |
| 25 | p / q | 25 | return p / q; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | fn acos32(x: f32) -> f32 { | 28 | fn acos32(x: f32) -> f32 { |
| ... | @@ -69,7 +69,7 @@ fn acos32(x: f32) -> f32 { | ... | @@ -69,7 +69,7 @@ fn acos32(x: f32) -> f32 { |
| 69 | const df = @bitCast(f32, jx & 0xFFFFF000); | 69 | const df = @bitCast(f32, jx & 0xFFFFF000); |
| 70 | const c = (z - df * df) / (s + df); | 70 | const c = (z - df * df) / (s + df); |
| 71 | const w = r32(z) * s + c; | 71 | const w = r32(z) * s + c; |
| 72 | 2 * (df + w) | 72 | return 2 * (df + w); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | fn r64(z: f64) -> f64 { | 75 | fn r64(z: f64) -> f64 { |
| ... | @@ -86,7 +86,7 @@ fn r64(z: f64) -> f64 { | ... | @@ -86,7 +86,7 @@ fn r64(z: f64) -> f64 { |
| 86 | 86 | ||
| 87 | const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5))))); | 87 | const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5))))); |
| 88 | const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4))); | 88 | const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4))); |
| 89 | p / q | 89 | return p / q; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | fn acos64(x: f64) -> f64 { | 92 | fn acos64(x: f64) -> f64 { |
| ... | @@ -138,7 +138,7 @@ fn acos64(x: f64) -> f64 { | ... | @@ -138,7 +138,7 @@ fn acos64(x: f64) -> f64 { |
| 138 | const df = @bitCast(f64, jx & 0xFFFFFFFF00000000); | 138 | const df = @bitCast(f64, jx & 0xFFFFFFFF00000000); |
| 139 | const c = (z - df * df) / (s + df); | 139 | const c = (z - df * df) / (s + df); |
| 140 | const w = r64(z) * s + c; | 140 | const w = r64(z) * s + c; |
| 141 | 2 * (df + w) | 141 | return 2 * (df + w); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | test "math.acos" { | 144 | test "math.acos" { |
std/math/acosh.zig+10-10| ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; |
| 9 | 9 | ||
| 10 | pub fn acosh(x: var) -> @typeOf(x) { | 10 | pub fn acosh(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
| 12 | switch (T) { | 12 | return switch (T) { |
| 13 | f32 => @inlineCall(acosh32, x), | 13 | f32 => acosh32(x), |
| 14 | f64 => @inlineCall(acosh64, x), | 14 | f64 => acosh64(x), |
| 15 | else => @compileError("acosh not implemented for " ++ @typeName(T)), | 15 | else => @compileError("acosh not implemented for " ++ @typeName(T)), |
| 16 | } | 16 | }; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | // acosh(x) = log(x + sqrt(x * x - 1)) | 19 | // acosh(x) = log(x + sqrt(x * x - 1)) |
| ... | @@ -23,15 +23,15 @@ fn acosh32(x: f32) -> f32 { | ... | @@ -23,15 +23,15 @@ fn acosh32(x: f32) -> f32 { |
| 23 | 23 | ||
| 24 | // |x| < 2, invalid if x < 1 or nan | 24 | // |x| < 2, invalid if x < 1 or nan |
| 25 | if (i < 0x3F800000 + (1 << 23)) { | 25 | if (i < 0x3F800000 + (1 << 23)) { |
| 26 | math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1))) | 26 | return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1))); |
| 27 | } | 27 | } |
| 28 | // |x| < 0x1p12 | 28 | // |x| < 0x1p12 |
| 29 | else if (i < 0x3F800000 + (12 << 23)) { | 29 | else if (i < 0x3F800000 + (12 << 23)) { |
| 30 | math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1))) | 30 | return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1))); |
| 31 | } | 31 | } |
| 32 | // |x| >= 0x1p12 | 32 | // |x| >= 0x1p12 |
| 33 | else { | 33 | else { |
| 34 | math.ln(x) + 0.693147180559945309417232121458176568 | 34 | return math.ln(x) + 0.693147180559945309417232121458176568; |
| 35 | } | 35 | } |
| 36 | } | 36 | } |
| 37 | 37 | ||
| ... | @@ -41,15 +41,15 @@ fn acosh64(x: f64) -> f64 { | ... | @@ -41,15 +41,15 @@ fn acosh64(x: f64) -> f64 { |
| 41 | 41 | ||
| 42 | // |x| < 2, invalid if x < 1 or nan | 42 | // |x| < 2, invalid if x < 1 or nan |
| 43 | if (e < 0x3FF + 1) { | 43 | if (e < 0x3FF + 1) { |
| 44 | math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1))) | 44 | return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1))); |
| 45 | } | 45 | } |
| 46 | // |x| < 0x1p26 | 46 | // |x| < 0x1p26 |
| 47 | else if (e < 0x3FF + 26) { | 47 | else if (e < 0x3FF + 26) { |
| 48 | math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1))) | 48 | return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1))); |
| 49 | } | 49 | } |
| 50 | // |x| >= 0x1p26 or nan | 50 | // |x| >= 0x1p26 or nan |
| 51 | else { | 51 | else { |
| 52 | math.ln(x) + 0.693147180559945309417232121458176568 | 52 | return math.ln(x) + 0.693147180559945309417232121458176568; |
| 53 | } | 53 | } |
| 54 | } | 54 | } |
| 55 | 55 |
std/math/asin.zig+11-11| ... | @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert; |
| 8 | 8 | ||
| 9 | pub fn asin(x: var) -> @typeOf(x) { | 9 | pub fn asin(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 10 | const T = @typeOf(x); |
| 11 | switch (T) { | 11 | return switch (T) { |
| 12 | f32 => @inlineCall(asin32, x), | 12 | f32 => asin32(x), |
| 13 | f64 => @inlineCall(asin64, x), | 13 | f64 => asin64(x), |
| 14 | else => @compileError("asin not implemented for " ++ @typeName(T)), | 14 | else => @compileError("asin not implemented for " ++ @typeName(T)), |
| 15 | } | 15 | }; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | fn r32(z: f32) -> f32 { | 18 | fn r32(z: f32) -> f32 { |
| ... | @@ -23,7 +23,7 @@ fn r32(z: f32) -> f32 { | ... | @@ -23,7 +23,7 @@ fn r32(z: f32) -> f32 { |
| 23 | 23 | ||
| 24 | const p = z * (pS0 + z * (pS1 + z * pS2)); | 24 | const p = z * (pS0 + z * (pS1 + z * pS2)); |
| 25 | const q = 1.0 + z * qS1; | 25 | const q = 1.0 + z * qS1; |
| 26 | p / q | 26 | return p / q; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | fn asin32(x: f32) -> f32 { | 29 | fn asin32(x: f32) -> f32 { |
| ... | @@ -58,9 +58,9 @@ fn asin32(x: f32) -> f32 { | ... | @@ -58,9 +58,9 @@ fn asin32(x: f32) -> f32 { |
| 58 | const fx = pio2 - 2 * (s + s * r32(z)); | 58 | const fx = pio2 - 2 * (s + s * r32(z)); |
| 59 | 59 | ||
| 60 | if (hx >> 31 != 0) { | 60 | if (hx >> 31 != 0) { |
| 61 | -fx | 61 | return -fx; |
| 62 | } else { | 62 | } else { |
| 63 | fx | 63 | return fx; |
| 64 | } | 64 | } |
| 65 | } | 65 | } |
| 66 | 66 | ||
| ... | @@ -78,7 +78,7 @@ fn r64(z: f64) -> f64 { | ... | @@ -78,7 +78,7 @@ fn r64(z: f64) -> f64 { |
| 78 | 78 | ||
| 79 | const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5))))); | 79 | const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5))))); |
| 80 | const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4))); | 80 | const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4))); |
| 81 | p / q | 81 | return p / q; |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | fn asin64(x: f64) -> f64 { | 84 | fn asin64(x: f64) -> f64 { |
| ... | @@ -119,7 +119,7 @@ fn asin64(x: f64) -> f64 { | ... | @@ -119,7 +119,7 @@ fn asin64(x: f64) -> f64 { |
| 119 | 119 | ||
| 120 | // |x| > 0.975 | 120 | // |x| > 0.975 |
| 121 | if (ix >= 0x3FEF3333) { | 121 | if (ix >= 0x3FEF3333) { |
| 122 | fx = pio2_hi - 2 * (s + s * r) | 122 | fx = pio2_hi - 2 * (s + s * r); |
| 123 | } else { | 123 | } else { |
| 124 | const jx = @bitCast(u64, s); | 124 | const jx = @bitCast(u64, s); |
| 125 | const df = @bitCast(f64, jx & 0xFFFFFFFF00000000); | 125 | const df = @bitCast(f64, jx & 0xFFFFFFFF00000000); |
| ... | @@ -128,9 +128,9 @@ fn asin64(x: f64) -> f64 { | ... | @@ -128,9 +128,9 @@ fn asin64(x: f64) -> f64 { |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | if (hx >> 31 != 0) { | 130 | if (hx >> 31 != 0) { |
| 131 | -fx | 131 | return -fx; |
| 132 | } else { | 132 | } else { |
| 133 | fx | 133 | return fx; |
| 134 | } | 134 | } |
| 135 | } | 135 | } |
| 136 | 136 |
std/math/asinh.zig+6-6| ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; |
| 9 | 9 | ||
| 10 | pub fn asinh(x: var) -> @typeOf(x) { | 10 | pub fn asinh(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
| 12 | switch (T) { | 12 | return switch (T) { |
| 13 | f32 => @inlineCall(asinh32, x), | 13 | f32 => asinh32(x), |
| 14 | f64 => @inlineCall(asinh64, x), | 14 | f64 => asinh64(x), |
| 15 | else => @compileError("asinh not implemented for " ++ @typeName(T)), | 15 | else => @compileError("asinh not implemented for " ++ @typeName(T)), |
| 16 | } | 16 | }; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | // asinh(x) = sign(x) * log(|x| + sqrt(x * x + 1)) ~= x - x^3/6 + o(x^5) | 19 | // asinh(x) = sign(x) * log(|x| + sqrt(x * x + 1)) ~= x - x^3/6 + o(x^5) |
| ... | @@ -46,7 +46,7 @@ fn asinh32(x: f32) -> f32 { | ... | @@ -46,7 +46,7 @@ fn asinh32(x: f32) -> f32 { |
| 46 | math.forceEval(x + 0x1.0p120); | 46 | math.forceEval(x + 0x1.0p120); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | if (s != 0) -rx else rx | 49 | return if (s != 0) -rx else rx; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | fn asinh64(x: f64) -> f64 { | 52 | fn asinh64(x: f64) -> f64 { |
| ... | @@ -77,7 +77,7 @@ fn asinh64(x: f64) -> f64 { | ... | @@ -77,7 +77,7 @@ fn asinh64(x: f64) -> f64 { |
| 77 | math.forceEval(x + 0x1.0p120); | 77 | math.forceEval(x + 0x1.0p120); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | if (s != 0) -rx else rx | 80 | return if (s != 0) -rx else rx; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | test "math.asinh" { | 83 | test "math.asinh" { |
std/math/atan.zig+13-13| ... | @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert; |
| 8 | 8 | ||
| 9 | pub fn atan(x: var) -> @typeOf(x) { | 9 | pub fn atan(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 10 | const T = @typeOf(x); |
| 11 | switch (T) { | 11 | return switch (T) { |
| 12 | f32 => @inlineCall(atan32, x), | 12 | f32 => atan32(x), |
| 13 | f64 => @inlineCall(atan64, x), | 13 | f64 => atan64(x), |
| 14 | else => @compileError("atan not implemented for " ++ @typeName(T)), | 14 | else => @compileError("atan not implemented for " ++ @typeName(T)), |
| 15 | } | 15 | }; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | fn atan32(x_: f32) -> f32 { | 18 | fn atan32(x_: f32) -> f32 { |
| ... | @@ -99,11 +99,11 @@ fn atan32(x_: f32) -> f32 { | ... | @@ -99,11 +99,11 @@ fn atan32(x_: f32) -> f32 { |
| 99 | const s1 = z * (aT[0] + w * (aT[2] + w * aT[4])); | 99 | const s1 = z * (aT[0] + w * (aT[2] + w * aT[4])); |
| 100 | const s2 = w * (aT[1] + w * aT[3]); | 100 | const s2 = w * (aT[1] + w * aT[3]); |
| 101 | 101 | ||
| 102 | if (id == null) { | 102 | if (id) |id_value| { |
| 103 | x - x * (s1 + s2) | 103 | const zz = atanhi[id_value] - ((x * (s1 + s2) - atanlo[id_value]) - x); |
| 104 | return if (sign != 0) -zz else zz; | ||
| 104 | } else { | 105 | } else { |
| 105 | const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x); | 106 | return x - x * (s1 + s2); |
| 106 | if (sign != 0) -zz else zz | ||
| 107 | } | 107 | } |
| 108 | } | 108 | } |
| 109 | 109 | ||
| ... | @@ -198,16 +198,16 @@ fn atan64(x_: f64) -> f64 { | ... | @@ -198,16 +198,16 @@ fn atan64(x_: f64) -> f64 { |
| 198 | const s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10]))))); | 198 | const s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10]))))); |
| 199 | const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9])))); | 199 | const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9])))); |
| 200 | 200 | ||
| 201 | if (id == null) { | 201 | if (id) |id_value| { |
| 202 | x - x * (s1 + s2) | 202 | const zz = atanhi[id_value] - ((x * (s1 + s2) - atanlo[id_value]) - x); |
| 203 | return if (sign != 0) -zz else zz; | ||
| 203 | } else { | 204 | } else { |
| 204 | const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x); | 205 | return x - x * (s1 + s2); |
| 205 | if (sign != 0) -zz else zz | ||
| 206 | } | 206 | } |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | test "math.atan" { | 209 | test "math.atan" { |
| 210 | assert(atan(f32(0.2)) == atan32(0.2)); | 210 | assert(@bitCast(u32, atan(f32(0.2))) == @bitCast(u32, atan32(0.2))); |
| 211 | assert(atan(f64(0.2)) == atan64(0.2)); | 211 | assert(atan(f64(0.2)) == atan64(0.2)); |
| 212 | } | 212 | } |
| 213 | 213 |
std/math/atan2.zig+10-10| ... | @@ -22,11 +22,11 @@ const math = @import("index.zig"); | ... | @@ -22,11 +22,11 @@ const math = @import("index.zig"); |
| 22 | const assert = @import("../debug.zig").assert; | 22 | const assert = @import("../debug.zig").assert; |
| 23 | 23 | ||
| 24 | fn atan2(comptime T: type, x: T, y: T) -> T { | 24 | fn atan2(comptime T: type, x: T, y: T) -> T { |
| 25 | switch (T) { | 25 | return switch (T) { |
| 26 | f32 => @inlineCall(atan2_32, x, y), | 26 | f32 => atan2_32(x, y), |
| 27 | f64 => @inlineCall(atan2_64, x, y), | 27 | f64 => atan2_64(x, y), |
| 28 | else => @compileError("atan2 not implemented for " ++ @typeName(T)), | 28 | else => @compileError("atan2 not implemented for " ++ @typeName(T)), |
| 29 | } | 29 | }; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | fn atan2_32(y: f32, x: f32) -> f32 { | 32 | fn atan2_32(y: f32, x: f32) -> f32 { |
| ... | @@ -97,11 +97,11 @@ fn atan2_32(y: f32, x: f32) -> f32 { | ... | @@ -97,11 +97,11 @@ fn atan2_32(y: f32, x: f32) -> f32 { |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | // z = atan(|y / x|) with correct underflow | 99 | // z = atan(|y / x|) with correct underflow |
| 100 | var z = { | 100 | var z = z: { |
| 101 | if ((m & 2) != 0 and iy + (26 << 23) < ix) { | 101 | if ((m & 2) != 0 and iy + (26 << 23) < ix) { |
| 102 | 0.0 | 102 | break :z 0.0; |
| 103 | } else { | 103 | } else { |
| 104 | math.atan(math.fabs(y / x)) | 104 | break :z math.atan(math.fabs(y / x)); |
| 105 | } | 105 | } |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| ... | @@ -187,11 +187,11 @@ fn atan2_64(y: f64, x: f64) -> f64 { | ... | @@ -187,11 +187,11 @@ fn atan2_64(y: f64, x: f64) -> f64 { |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | // z = atan(|y / x|) with correct underflow | 189 | // z = atan(|y / x|) with correct underflow |
| 190 | var z = { | 190 | var z = z: { |
| 191 | if ((m & 2) != 0 and iy +% (64 << 20) < ix) { | 191 | if ((m & 2) != 0 and iy +% (64 << 20) < ix) { |
| 192 | 0.0 | 192 | break :z 0.0; |
| 193 | } else { | 193 | } else { |
| 194 | math.atan(math.fabs(y / x)) | 194 | break :z math.atan(math.fabs(y / x)); |
| 195 | } | 195 | } |
| 196 | }; | 196 | }; |
| 197 | 197 |
std/math/atanh.zig+7-7| ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; |
| 9 | 9 | ||
| 10 | pub fn atanh(x: var) -> @typeOf(x) { | 10 | pub fn atanh(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
| 12 | switch (T) { | 12 | return switch (T) { |
| 13 | f32 => @inlineCall(atanh_32, x), | 13 | f32 => atanh_32(x), |
| 14 | f64 => @inlineCall(atanh_64, x), | 14 | f64 => atanh_64(x), |
| 15 | else => @compileError("atanh not implemented for " ++ @typeName(T)), | 15 | else => @compileError("atanh not implemented for " ++ @typeName(T)), |
| 16 | } | 16 | }; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | // atanh(x) = log((1 + x) / (1 - x)) / 2 = log1p(2x / (1 - x)) / 2 ~= x + x^3 / 3 + o(x^5) | 19 | // atanh(x) = log((1 + x) / (1 - x)) / 2 = log1p(2x / (1 - x)) / 2 ~= x + x^3 / 3 + o(x^5) |
| ... | @@ -32,7 +32,7 @@ fn atanh_32(x: f32) -> f32 { | ... | @@ -32,7 +32,7 @@ fn atanh_32(x: f32) -> f32 { |
| 32 | if (u < 0x3F800000 - (32 << 23)) { | 32 | if (u < 0x3F800000 - (32 << 23)) { |
| 33 | // underflow | 33 | // underflow |
| 34 | if (u < (1 << 23)) { | 34 | if (u < (1 << 23)) { |
| 35 | math.forceEval(y * y) | 35 | math.forceEval(y * y); |
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | // |x| < 0.5 | 38 | // |x| < 0.5 |
| ... | @@ -43,7 +43,7 @@ fn atanh_32(x: f32) -> f32 { | ... | @@ -43,7 +43,7 @@ fn atanh_32(x: f32) -> f32 { |
| 43 | y = 0.5 * math.log1p(2 * (y / (1 - y))); | 43 | y = 0.5 * math.log1p(2 * (y / (1 - y))); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | if (s != 0) -y else y | 46 | return if (s != 0) -y else y; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | fn atanh_64(x: f64) -> f64 { | 49 | fn atanh_64(x: f64) -> f64 { |
| ... | @@ -72,7 +72,7 @@ fn atanh_64(x: f64) -> f64 { | ... | @@ -72,7 +72,7 @@ fn atanh_64(x: f64) -> f64 { |
| 72 | y = 0.5 * math.log1p(2 * (y / (1 - y))); | 72 | y = 0.5 * math.log1p(2 * (y / (1 - y))); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | if (s != 0) -y else y | 75 | return if (s != 0) -y else y; |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | test "math.atanh" { | 78 | test "math.atanh" { |
std/math/cbrt.zig+6-6| ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; |
| 9 | 9 | ||
| 10 | pub fn cbrt(x: var) -> @typeOf(x) { | 10 | pub fn cbrt(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
| 12 | switch (T) { | 12 | return switch (T) { |
| 13 | f32 => @inlineCall(cbrt32, x), | 13 | f32 => cbrt32(x), |
| 14 | f64 => @inlineCall(cbrt64, x), | 14 | f64 => cbrt64(x), |
| 15 | else => @compileError("cbrt not implemented for " ++ @typeName(T)), | 15 | else => @compileError("cbrt not implemented for " ++ @typeName(T)), |
| 16 | } | 16 | }; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | fn cbrt32(x: f32) -> f32 { | 19 | fn cbrt32(x: f32) -> f32 { |
| ... | @@ -53,7 +53,7 @@ fn cbrt32(x: f32) -> f32 { | ... | @@ -53,7 +53,7 @@ fn cbrt32(x: f32) -> f32 { |
| 53 | r = t * t * t; | 53 | r = t * t * t; |
| 54 | t = t * (f64(x) + x + r) / (x + r + r); | 54 | t = t * (f64(x) + x + r) / (x + r + r); |
| 55 | 55 | ||
| 56 | f32(t) | 56 | return f32(t); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | fn cbrt64(x: f64) -> f64 { | 59 | fn cbrt64(x: f64) -> f64 { |
| ... | @@ -109,7 +109,7 @@ fn cbrt64(x: f64) -> f64 { | ... | @@ -109,7 +109,7 @@ fn cbrt64(x: f64) -> f64 { |
| 109 | var w = t + t; | 109 | var w = t + t; |
| 110 | q = (q - t) / (w + q); | 110 | q = (q - t) / (w + q); |
| 111 | 111 | ||
| 112 | t + t * q | 112 | return t + t * q; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | test "math.cbrt" { | 115 | test "math.cbrt" { |
std/math/ceil.zig+10-10| ... | @@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert; |
| 10 | 10 | ||
| 11 | pub fn ceil(x: var) -> @typeOf(x) { | 11 | pub fn ceil(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
| 13 | switch (T) { | 13 | return switch (T) { |
| 14 | f32 => @inlineCall(ceil32, x), | 14 | f32 => ceil32(x), |
| 15 | f64 => @inlineCall(ceil64, x), | 15 | f64 => ceil64(x), |
| 16 | else => @compileError("ceil not implemented for " ++ @typeName(T)), | 16 | else => @compileError("ceil not implemented for " ++ @typeName(T)), |
| 17 | } | 17 | }; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | fn ceil32(x: f32) -> f32 { | 20 | fn ceil32(x: f32) -> f32 { |
| ... | @@ -39,13 +39,13 @@ fn ceil32(x: f32) -> f32 { | ... | @@ -39,13 +39,13 @@ fn ceil32(x: f32) -> f32 { |
| 39 | u += m; | 39 | u += m; |
| 40 | } | 40 | } |
| 41 | u &= ~m; | 41 | u &= ~m; |
| 42 | @bitCast(f32, u) | 42 | return @bitCast(f32, u); |
| 43 | } else { | 43 | } else { |
| 44 | math.forceEval(x + 0x1.0p120); | 44 | math.forceEval(x + 0x1.0p120); |
| 45 | if (u >> 31 != 0) { | 45 | if (u >> 31 != 0) { |
| 46 | return -0.0; | 46 | return -0.0; |
| 47 | } else { | 47 | } else { |
| 48 | 1.0 | 48 | return 1.0; |
| 49 | } | 49 | } |
| 50 | } | 50 | } |
| 51 | } | 51 | } |
| ... | @@ -70,14 +70,14 @@ fn ceil64(x: f64) -> f64 { | ... | @@ -70,14 +70,14 @@ fn ceil64(x: f64) -> f64 { |
| 70 | if (e <= 0x3FF-1) { | 70 | if (e <= 0x3FF-1) { |
| 71 | math.forceEval(y); | 71 | math.forceEval(y); |
| 72 | if (u >> 63 != 0) { | 72 | if (u >> 63 != 0) { |
| 73 | return -0.0; // Compiler requires return. | 73 | return -0.0; |
| 74 | } else { | 74 | } else { |
| 75 | 1.0 | 75 | return 1.0; |
| 76 | } | 76 | } |
| 77 | } else if (y < 0) { | 77 | } else if (y < 0) { |
| 78 | x + y + 1 | 78 | return x + y + 1; |
| 79 | } else { | 79 | } else { |
| 80 | x + y | 80 | return x + y; |
| 81 | } | 81 | } |
| 82 | } | 82 | } |
| 83 | 83 |
std/math/copysign.zig+6-6| ... | @@ -2,11 +2,11 @@ const math = @import("index.zig"); | ... | @@ -2,11 +2,11 @@ const math = @import("index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const assert = @import("../debug.zig").assert; |
| 3 | 3 | ||
| 4 | pub fn copysign(comptime T: type, x: T, y: T) -> T { | 4 | pub fn copysign(comptime T: type, x: T, y: T) -> T { |
| 5 | switch (T) { | 5 | return switch (T) { |
| 6 | f32 => @inlineCall(copysign32, x, y), | 6 | f32 => copysign32(x, y), |
| 7 | f64 => @inlineCall(copysign64, x, y), | 7 | f64 => copysign64(x, y), |
| 8 | else => @compileError("copysign not implemented for " ++ @typeName(T)), | 8 | else => @compileError("copysign not implemented for " ++ @typeName(T)), |
| 9 | } | 9 | }; |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | fn copysign32(x: f32, y: f32) -> f32 { | 12 | fn copysign32(x: f32, y: f32) -> f32 { |
| ... | @@ -15,7 +15,7 @@ fn copysign32(x: f32, y: f32) -> f32 { | ... | @@ -15,7 +15,7 @@ fn copysign32(x: f32, y: f32) -> f32 { |
| 15 | 15 | ||
| 16 | const h1 = ux & (@maxValue(u32) / 2); | 16 | const h1 = ux & (@maxValue(u32) / 2); |
| 17 | const h2 = uy & (u32(1) << 31); | 17 | const h2 = uy & (u32(1) << 31); |
| 18 | @bitCast(f32, h1 | h2) | 18 | return @bitCast(f32, h1 | h2); |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | fn copysign64(x: f64, y: f64) -> f64 { | 21 | fn copysign64(x: f64, y: f64) -> f64 { |
| ... | @@ -24,7 +24,7 @@ fn copysign64(x: f64, y: f64) -> f64 { | ... | @@ -24,7 +24,7 @@ fn copysign64(x: f64, y: f64) -> f64 { |
| 24 | 24 | ||
| 25 | const h1 = ux & (@maxValue(u64) / 2); | 25 | const h1 = ux & (@maxValue(u64) / 2); |
| 26 | const h2 = uy & (u64(1) << 63); | 26 | const h2 = uy & (u64(1) << 63); |
| 27 | @bitCast(f64, h1 | h2) | 27 | return @bitCast(f64, h1 | h2); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | test "math.copysign" { | 30 | test "math.copysign" { |
std/math/cos.zig+14-14| ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; |
| 9 | 9 | ||
| 10 | pub fn cos(x: var) -> @typeOf(x) { | 10 | pub fn cos(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
| 12 | switch (T) { | 12 | return switch (T) { |
| 13 | f32 => @inlineCall(cos32, x), | 13 | f32 => cos32(x), |
| 14 | f64 => @inlineCall(cos64, x), | 14 | f64 => cos64(x), |
| 15 | else => @compileError("cos not implemented for " ++ @typeName(T)), | 15 | else => @compileError("cos not implemented for " ++ @typeName(T)), |
| 16 | } | 16 | }; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | // sin polynomial coefficients | 19 | // sin polynomial coefficients |
| ... | @@ -73,18 +73,18 @@ fn cos32(x_: f32) -> f32 { | ... | @@ -73,18 +73,18 @@ fn cos32(x_: f32) -> f32 { |
| 73 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | 73 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; |
| 74 | const w = z * z; | 74 | const w = z * z; |
| 75 | 75 | ||
| 76 | const r = { | 76 | const r = r: { |
| 77 | if (j == 1 or j == 2) { | 77 | if (j == 1 or j == 2) { |
| 78 | z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))) | 78 | break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); |
| 79 | } else { | 79 | } else { |
| 80 | 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))) | 80 | break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); |
| 81 | } | 81 | } |
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | if (sign) { | 84 | if (sign) { |
| 85 | -r | 85 | return -r; |
| 86 | } else { | 86 | } else { |
| 87 | r | 87 | return r; |
| 88 | } | 88 | } |
| 89 | } | 89 | } |
| 90 | 90 | ||
| ... | @@ -124,18 +124,18 @@ fn cos64(x_: f64) -> f64 { | ... | @@ -124,18 +124,18 @@ fn cos64(x_: f64) -> f64 { |
| 124 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | 124 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; |
| 125 | const w = z * z; | 125 | const w = z * z; |
| 126 | 126 | ||
| 127 | const r = { | 127 | const r = r: { |
| 128 | if (j == 1 or j == 2) { | 128 | if (j == 1 or j == 2) { |
| 129 | z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))) | 129 | break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); |
| 130 | } else { | 130 | } else { |
| 131 | 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))) | 131 | break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); |
| 132 | } | 132 | } |
| 133 | }; | 133 | }; |
| 134 | 134 | ||
| 135 | if (sign) { | 135 | if (sign) { |
| 136 | -r | 136 | return -r; |
| 137 | } else { | 137 | } else { |
| 138 | r | 138 | return r; |
| 139 | } | 139 | } |
| 140 | } | 140 | } |
| 141 | 141 |
std/math/cosh.zig+6-6| ... | @@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert; |
| 11 | 11 | ||
| 12 | pub fn cosh(x: var) -> @typeOf(x) { | 12 | pub fn cosh(x: var) -> @typeOf(x) { |
| 13 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
| 14 | switch (T) { | 14 | return switch (T) { |
| 15 | f32 => @inlineCall(cosh32, x), | 15 | f32 => cosh32(x), |
| 16 | f64 => @inlineCall(cosh64, x), | 16 | f64 => cosh64(x), |
| 17 | else => @compileError("cosh not implemented for " ++ @typeName(T)), | 17 | else => @compileError("cosh not implemented for " ++ @typeName(T)), |
| 18 | } | 18 | }; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | // cosh(x) = (exp(x) + 1 / exp(x)) / 2 | 21 | // cosh(x) = (exp(x) + 1 / exp(x)) / 2 |
| ... | @@ -43,7 +43,7 @@ fn cosh32(x: f32) -> f32 { | ... | @@ -43,7 +43,7 @@ fn cosh32(x: f32) -> f32 { |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | // |x| > log(FLT_MAX) or nan | 45 | // |x| > log(FLT_MAX) or nan |
| 46 | expo2(ax) | 46 | return expo2(ax); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | fn cosh64(x: f64) -> f64 { | 49 | fn cosh64(x: f64) -> f64 { |
| ... | @@ -76,7 +76,7 @@ fn cosh64(x: f64) -> f64 { | ... | @@ -76,7 +76,7 @@ fn cosh64(x: f64) -> f64 { |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | // |x| > log(CBL_MAX) or nan | 78 | // |x| > log(CBL_MAX) or nan |
| 79 | expo2(ax) | 79 | return expo2(ax); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | test "math.cosh" { | 82 | test "math.cosh" { |
std/math/exp.zig+8-8| ... | @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert; |
| 8 | 8 | ||
| 9 | pub fn exp(x: var) -> @typeOf(x) { | 9 | pub fn exp(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 10 | const T = @typeOf(x); |
| 11 | switch (T) { | 11 | return switch (T) { |
| 12 | f32 => @inlineCall(exp32, x), | 12 | f32 => exp32(x), |
| 13 | f64 => @inlineCall(exp64, x), | 13 | f64 => exp64(x), |
| 14 | else => @compileError("exp not implemented for " ++ @typeName(T)), | 14 | else => @compileError("exp not implemented for " ++ @typeName(T)), |
| 15 | } | 15 | }; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | fn exp32(x_: f32) -> f32 { | 18 | fn exp32(x_: f32) -> f32 { |
| ... | @@ -86,9 +86,9 @@ fn exp32(x_: f32) -> f32 { | ... | @@ -86,9 +86,9 @@ fn exp32(x_: f32) -> f32 { |
| 86 | const y = 1 + (x * c / (2 - c) - lo + hi); | 86 | const y = 1 + (x * c / (2 - c) - lo + hi); |
| 87 | 87 | ||
| 88 | if (k == 0) { | 88 | if (k == 0) { |
| 89 | y | 89 | return y; |
| 90 | } else { | 90 | } else { |
| 91 | math.scalbn(y, k) | 91 | return math.scalbn(y, k); |
| 92 | } | 92 | } |
| 93 | } | 93 | } |
| 94 | 94 | ||
| ... | @@ -172,9 +172,9 @@ fn exp64(x_: f64) -> f64 { | ... | @@ -172,9 +172,9 @@ fn exp64(x_: f64) -> f64 { |
| 172 | const y = 1 + (x * c / (2 - c) - lo + hi); | 172 | const y = 1 + (x * c / (2 - c) - lo + hi); |
| 173 | 173 | ||
| 174 | if (k == 0) { | 174 | if (k == 0) { |
| 175 | y | 175 | return y; |
| 176 | } else { | 176 | } else { |
| 177 | math.scalbn(y, k) | 177 | return math.scalbn(y, k); |
| 178 | } | 178 | } |
| 179 | } | 179 | } |
| 180 | 180 |
std/math/exp2.zig+6-6| ... | @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert; |
| 8 | 8 | ||
| 9 | pub fn exp2(x: var) -> @typeOf(x) { | 9 | pub fn exp2(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 10 | const T = @typeOf(x); |
| 11 | switch (T) { | 11 | return switch (T) { |
| 12 | f32 => @inlineCall(exp2_32, x), | 12 | f32 => exp2_32(x), |
| 13 | f64 => @inlineCall(exp2_64, x), | 13 | f64 => exp2_64(x), |
| 14 | else => @compileError("exp2 not implemented for " ++ @typeName(T)), | 14 | else => @compileError("exp2 not implemented for " ++ @typeName(T)), |
| 15 | } | 15 | }; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | const exp2ft = []const f64 { | 18 | const exp2ft = []const f64 { |
| ... | @@ -88,7 +88,7 @@ fn exp2_32(x: f32) -> f32 { | ... | @@ -88,7 +88,7 @@ fn exp2_32(x: f32) -> f32 { |
| 88 | var r: f64 = exp2ft[i0]; | 88 | var r: f64 = exp2ft[i0]; |
| 89 | const t: f64 = r * z; | 89 | const t: f64 = r * z; |
| 90 | r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); | 90 | r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); |
| 91 | f32(r * uk) | 91 | return f32(r * uk); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | const exp2dt = []f64 { | 94 | const exp2dt = []f64 { |
| ... | @@ -414,7 +414,7 @@ fn exp2_64(x: f64) -> f64 { | ... | @@ -414,7 +414,7 @@ fn exp2_64(x: f64) -> f64 { |
| 414 | z -= exp2dt[2 * i0 + 1]; | 414 | z -= exp2dt[2 * i0 + 1]; |
| 415 | const r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); | 415 | const r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); |
| 416 | 416 | ||
| 417 | math.scalbn(r, ik) | 417 | return math.scalbn(r, ik); |
| 418 | } | 418 | } |
| 419 | 419 | ||
| 420 | test "math.exp2" { | 420 | test "math.exp2" { |
std/math/expm1.zig+4-4| ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; |
| 9 | 9 | ||
| 10 | pub fn expm1(x: var) -> @typeOf(x) { | 10 | pub fn expm1(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
| 12 | switch (T) { | 12 | return switch (T) { |
| 13 | f32 => @inlineCall(expm1_32, x), | 13 | f32 => expm1_32(x), |
| 14 | f64 => @inlineCall(expm1_64, x), | 14 | f64 => expm1_64(x), |
| 15 | else => @compileError("exp1m not implemented for " ++ @typeName(T)), | 15 | else => @compileError("exp1m not implemented for " ++ @typeName(T)), |
| 16 | } | 16 | }; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | fn expm1_32(x_: f32) -> f32 { | 19 | fn expm1_32(x_: f32) -> f32 { |
std/math/expo2.zig+4-4| ... | @@ -2,11 +2,11 @@ const math = @import("index.zig"); | ... | @@ -2,11 +2,11 @@ const math = @import("index.zig"); |
| 2 | 2 | ||
| 3 | pub fn expo2(x: var) -> @typeOf(x) { | 3 | pub fn expo2(x: var) -> @typeOf(x) { |
| 4 | const T = @typeOf(x); | 4 | const T = @typeOf(x); |
| 5 | switch (T) { | 5 | return switch (T) { |
| 6 | f32 => expo2f(x), | 6 | f32 => expo2f(x), |
| 7 | f64 => expo2d(x), | 7 | f64 => expo2d(x), |
| 8 | else => @compileError("expo2 not implemented for " ++ @typeName(T)), | 8 | else => @compileError("expo2 not implemented for " ++ @typeName(T)), |
| 9 | } | 9 | }; |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | fn expo2f(x: f32) -> f32 { | 12 | fn expo2f(x: f32) -> f32 { |
| ... | @@ -15,7 +15,7 @@ fn expo2f(x: f32) -> f32 { | ... | @@ -15,7 +15,7 @@ fn expo2f(x: f32) -> f32 { |
| 15 | 15 | ||
| 16 | const u = (0x7F + k / 2) << 23; | 16 | const u = (0x7F + k / 2) << 23; |
| 17 | const scale = @bitCast(f32, u); | 17 | const scale = @bitCast(f32, u); |
| 18 | math.exp(x - kln2) * scale * scale | 18 | return math.exp(x - kln2) * scale * scale; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | fn expo2d(x: f64) -> f64 { | 21 | fn expo2d(x: f64) -> f64 { |
| ... | @@ -24,5 +24,5 @@ fn expo2d(x: f64) -> f64 { | ... | @@ -24,5 +24,5 @@ fn expo2d(x: f64) -> f64 { |
| 24 | 24 | ||
| 25 | const u = (0x3FF + k / 2) << 20; | 25 | const u = (0x3FF + k / 2) << 20; |
| 26 | const scale = @bitCast(f64, u64(u) << 32); | 26 | const scale = @bitCast(f64, u64(u) << 32); |
| 27 | math.exp(x - kln2) * scale * scale | 27 | return math.exp(x - kln2) * scale * scale; |
| 28 | } | 28 | } |
std/math/fabs.zig+6-6| ... | @@ -8,23 +8,23 @@ const assert = @import("../debug.zig").assert; | ... | @@ -8,23 +8,23 @@ const assert = @import("../debug.zig").assert; |
| 8 | 8 | ||
| 9 | pub fn fabs(x: var) -> @typeOf(x) { | 9 | pub fn fabs(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 10 | const T = @typeOf(x); |
| 11 | switch (T) { | 11 | return switch (T) { |
| 12 | f32 => @inlineCall(fabs32, x), | 12 | f32 => fabs32(x), |
| 13 | f64 => @inlineCall(fabs64, x), | 13 | f64 => fabs64(x), |
| 14 | else => @compileError("fabs not implemented for " ++ @typeName(T)), | 14 | else => @compileError("fabs not implemented for " ++ @typeName(T)), |
| 15 | } | 15 | }; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | fn fabs32(x: f32) -> f32 { | 18 | fn fabs32(x: f32) -> f32 { |
| 19 | var u = @bitCast(u32, x); | 19 | var u = @bitCast(u32, x); |
| 20 | u &= 0x7FFFFFFF; | 20 | u &= 0x7FFFFFFF; |
| 21 | @bitCast(f32, u) | 21 | return @bitCast(f32, u); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | fn fabs64(x: f64) -> f64 { | 24 | fn fabs64(x: f64) -> f64 { |
| 25 | var u = @bitCast(u64, x); | 25 | var u = @bitCast(u64, x); |
| 26 | u &= @maxValue(u64) >> 1; | 26 | u &= @maxValue(u64) >> 1; |
| 27 | @bitCast(f64, u) | 27 | return @bitCast(f64, u); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | test "math.fabs" { | 30 | test "math.fabs" { |
std/math/floor.zig+11-11| ... | @@ -10,11 +10,11 @@ const math = @import("index.zig"); | ... | @@ -10,11 +10,11 @@ const math = @import("index.zig"); |
| 10 | 10 | ||
| 11 | pub fn floor(x: var) -> @typeOf(x) { | 11 | pub fn floor(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
| 13 | switch (T) { | 13 | return switch (T) { |
| 14 | f32 => @inlineCall(floor32, x), | 14 | f32 => floor32(x), |
| 15 | f64 => @inlineCall(floor64, x), | 15 | f64 => floor64(x), |
| 16 | else => @compileError("floor not implemented for " ++ @typeName(T)), | 16 | else => @compileError("floor not implemented for " ++ @typeName(T)), |
| 17 | } | 17 | }; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | fn floor32(x: f32) -> f32 { | 20 | fn floor32(x: f32) -> f32 { |
| ... | @@ -40,13 +40,13 @@ fn floor32(x: f32) -> f32 { | ... | @@ -40,13 +40,13 @@ fn floor32(x: f32) -> f32 { |
| 40 | if (u >> 31 != 0) { | 40 | if (u >> 31 != 0) { |
| 41 | u += m; | 41 | u += m; |
| 42 | } | 42 | } |
| 43 | @bitCast(f32, u & ~m) | 43 | return @bitCast(f32, u & ~m); |
| 44 | } else { | 44 | } else { |
| 45 | math.forceEval(x + 0x1.0p120); | 45 | math.forceEval(x + 0x1.0p120); |
| 46 | if (u >> 31 == 0) { | 46 | if (u >> 31 == 0) { |
| 47 | return 0.0; // Compiler requires return | 47 | return 0.0; |
| 48 | } else { | 48 | } else { |
| 49 | -1.0 | 49 | return -1.0; |
| 50 | } | 50 | } |
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| ... | @@ -71,14 +71,14 @@ fn floor64(x: f64) -> f64 { | ... | @@ -71,14 +71,14 @@ fn floor64(x: f64) -> f64 { |
| 71 | if (e <= 0x3FF-1) { | 71 | if (e <= 0x3FF-1) { |
| 72 | math.forceEval(y); | 72 | math.forceEval(y); |
| 73 | if (u >> 63 != 0) { | 73 | if (u >> 63 != 0) { |
| 74 | return -1.0; // Compiler requires return. | 74 | return -1.0; |
| 75 | } else { | 75 | } else { |
| 76 | 0.0 | 76 | return 0.0; |
| 77 | } | 77 | } |
| 78 | } else if (y > 0) { | 78 | } else if (y > 0) { |
| 79 | x + y - 1 | 79 | return x + y - 1; |
| 80 | } else { | 80 | } else { |
| 81 | x + y | 81 | return x + y; |
| 82 | } | 82 | } |
| 83 | } | 83 | } |
| 84 | 84 |
std/math/fma.zig+12-12| ... | @@ -2,11 +2,11 @@ const math = @import("index.zig"); | ... | @@ -2,11 +2,11 @@ const math = @import("index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const assert = @import("../debug.zig").assert; |
| 3 | 3 | ||
| 4 | pub fn fma(comptime T: type, x: T, y: T, z: T) -> T { | 4 | pub fn fma(comptime T: type, x: T, y: T, z: T) -> T { |
| 5 | switch (T) { | 5 | return switch (T) { |
| 6 | f32 => @inlineCall(fma32, x, y, z), | 6 | f32 => fma32(x, y, z), |
| 7 | f64 => @inlineCall(fma64, x, y ,z), | 7 | f64 => fma64(x, y ,z), |
| 8 | else => @compileError("fma not implemented for " ++ @typeName(T)), | 8 | else => @compileError("fma not implemented for " ++ @typeName(T)), |
| 9 | } | 9 | }; |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | fn fma32(x: f32, y: f32, z: f32) -> f32 { | 12 | fn fma32(x: f32, y: f32, z: f32) -> f32 { |
| ... | @@ -16,10 +16,10 @@ fn fma32(x: f32, y: f32, z: f32) -> f32 { | ... | @@ -16,10 +16,10 @@ fn fma32(x: f32, y: f32, z: f32) -> f32 { |
| 16 | const e = (u >> 52) & 0x7FF; | 16 | const e = (u >> 52) & 0x7FF; |
| 17 | 17 | ||
| 18 | if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or xy_z - xy == z) { | 18 | if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or xy_z - xy == z) { |
| 19 | f32(xy_z) | 19 | return f32(xy_z); |
| 20 | } else { | 20 | } else { |
| 21 | // TODO: Handle inexact case with double-rounding | 21 | // TODO: Handle inexact case with double-rounding |
| 22 | f32(xy_z) | 22 | return f32(xy_z); |
| 23 | } | 23 | } |
| 24 | } | 24 | } |
| 25 | 25 | ||
| ... | @@ -64,9 +64,9 @@ fn fma64(x: f64, y: f64, z: f64) -> f64 { | ... | @@ -64,9 +64,9 @@ fn fma64(x: f64, y: f64, z: f64) -> f64 { |
| 64 | 64 | ||
| 65 | const adj = add_adjusted(r.lo, xy.lo); | 65 | const adj = add_adjusted(r.lo, xy.lo); |
| 66 | if (spread + math.ilogb(r.hi) > -1023) { | 66 | if (spread + math.ilogb(r.hi) > -1023) { |
| 67 | math.scalbn(r.hi + adj, spread) | 67 | return math.scalbn(r.hi + adj, spread); |
| 68 | } else { | 68 | } else { |
| 69 | add_and_denorm(r.hi, adj, spread) | 69 | return add_and_denorm(r.hi, adj, spread); |
| 70 | } | 70 | } |
| 71 | } | 71 | } |
| 72 | 72 | ||
| ... | @@ -77,7 +77,7 @@ fn dd_add(a: f64, b: f64) -> dd { | ... | @@ -77,7 +77,7 @@ fn dd_add(a: f64, b: f64) -> dd { |
| 77 | ret.hi = a + b; | 77 | ret.hi = a + b; |
| 78 | const s = ret.hi - a; | 78 | const s = ret.hi - a; |
| 79 | ret.lo = (a - (ret.hi - s)) + (b - s); | 79 | ret.lo = (a - (ret.hi - s)) + (b - s); |
| 80 | ret | 80 | return ret; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | fn dd_mul(a: f64, b: f64) -> dd { | 83 | fn dd_mul(a: f64, b: f64) -> dd { |
| ... | @@ -99,7 +99,7 @@ fn dd_mul(a: f64, b: f64) -> dd { | ... | @@ -99,7 +99,7 @@ fn dd_mul(a: f64, b: f64) -> dd { |
| 99 | 99 | ||
| 100 | ret.hi = p + q; | 100 | ret.hi = p + q; |
| 101 | ret.lo = p - ret.hi + q + la * lb; | 101 | ret.lo = p - ret.hi + q + la * lb; |
| 102 | ret | 102 | return ret; |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | fn add_adjusted(a: f64, b: f64) -> f64 { | 105 | fn add_adjusted(a: f64, b: f64) -> f64 { |
| ... | @@ -113,7 +113,7 @@ fn add_adjusted(a: f64, b: f64) -> f64 { | ... | @@ -113,7 +113,7 @@ fn add_adjusted(a: f64, b: f64) -> f64 { |
| 113 | sum.hi = @bitCast(f64, uhii); | 113 | sum.hi = @bitCast(f64, uhii); |
| 114 | } | 114 | } |
| 115 | } | 115 | } |
| 116 | sum.hi | 116 | return sum.hi; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 { | 119 | fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 { |
| ... | @@ -127,7 +127,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 { | ... | @@ -127,7 +127,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 { |
| 127 | sum.hi = @bitCast(f64, uhii); | 127 | sum.hi = @bitCast(f64, uhii); |
| 128 | } | 128 | } |
| 129 | } | 129 | } |
| 130 | math.scalbn(sum.hi, scale) | 130 | return math.scalbn(sum.hi, scale); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | test "math.fma" { | 133 | test "math.fma" { |
std/math/frexp.zig+8-8| ... | @@ -8,21 +8,21 @@ const math = @import("index.zig"); | ... | @@ -8,21 +8,21 @@ const math = @import("index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const assert = @import("../debug.zig").assert; |
| 9 | 9 | ||
| 10 | fn frexp_result(comptime T: type) -> type { | 10 | fn frexp_result(comptime T: type) -> type { |
| 11 | struct { | 11 | return struct { |
| 12 | significand: T, | 12 | significand: T, |
| 13 | exponent: i32, | 13 | exponent: i32, |
| 14 | } | 14 | }; |
| 15 | } | 15 | } |
| 16 | pub const frexp32_result = frexp_result(f32); | 16 | pub const frexp32_result = frexp_result(f32); |
| 17 | pub const frexp64_result = frexp_result(f64); | 17 | pub const frexp64_result = frexp_result(f64); |
| 18 | 18 | ||
| 19 | pub fn frexp(x: var) -> frexp_result(@typeOf(x)) { | 19 | pub fn frexp(x: var) -> frexp_result(@typeOf(x)) { |
| 20 | const T = @typeOf(x); | 20 | const T = @typeOf(x); |
| 21 | switch (T) { | 21 | return switch (T) { |
| 22 | f32 => @inlineCall(frexp32, x), | 22 | f32 => frexp32(x), |
| 23 | f64 => @inlineCall(frexp64, x), | 23 | f64 => frexp64(x), |
| 24 | else => @compileError("frexp not implemented for " ++ @typeName(T)), | 24 | else => @compileError("frexp not implemented for " ++ @typeName(T)), |
| 25 | } | 25 | }; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | fn frexp32(x: f32) -> frexp32_result { | 28 | fn frexp32(x: f32) -> frexp32_result { |
| ... | @@ -59,7 +59,7 @@ fn frexp32(x: f32) -> frexp32_result { | ... | @@ -59,7 +59,7 @@ fn frexp32(x: f32) -> frexp32_result { |
| 59 | y &= 0x807FFFFF; | 59 | y &= 0x807FFFFF; |
| 60 | y |= 0x3F000000; | 60 | y |= 0x3F000000; |
| 61 | result.significand = @bitCast(f32, y); | 61 | result.significand = @bitCast(f32, y); |
| 62 | result | 62 | return result; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | fn frexp64(x: f64) -> frexp64_result { | 65 | fn frexp64(x: f64) -> frexp64_result { |
| ... | @@ -96,7 +96,7 @@ fn frexp64(x: f64) -> frexp64_result { | ... | @@ -96,7 +96,7 @@ fn frexp64(x: f64) -> frexp64_result { |
| 96 | y &= 0x800FFFFFFFFFFFFF; | 96 | y &= 0x800FFFFFFFFFFFFF; |
| 97 | y |= 0x3FE0000000000000; | 97 | y |= 0x3FE0000000000000; |
| 98 | result.significand = @bitCast(f64, y); | 98 | result.significand = @bitCast(f64, y); |
| 99 | result | 99 | return result; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | test "math.frexp" { | 102 | test "math.frexp" { |
std/math/hypot.zig+6-6| ... | @@ -9,11 +9,11 @@ const math = @import("index.zig"); | ... | @@ -9,11 +9,11 @@ const math = @import("index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const assert = @import("../debug.zig").assert; |
| 10 | 10 | ||
| 11 | pub fn hypot(comptime T: type, x: T, y: T) -> T { | 11 | pub fn hypot(comptime T: type, x: T, y: T) -> T { |
| 12 | switch (T) { | 12 | return switch (T) { |
| 13 | f32 => @inlineCall(hypot32, x, y), | 13 | f32 => hypot32(x, y), |
| 14 | f64 => @inlineCall(hypot64, x, y), | 14 | f64 => hypot64(x, y), |
| 15 | else => @compileError("hypot not implemented for " ++ @typeName(T)), | 15 | else => @compileError("hypot not implemented for " ++ @typeName(T)), |
| 16 | } | 16 | }; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | fn hypot32(x: f32, y: f32) -> f32 { | 19 | fn hypot32(x: f32, y: f32) -> f32 { |
| ... | @@ -48,7 +48,7 @@ fn hypot32(x: f32, y: f32) -> f32 { | ... | @@ -48,7 +48,7 @@ fn hypot32(x: f32, y: f32) -> f32 { |
| 48 | yy *= 0x1.0p-90; | 48 | yy *= 0x1.0p-90; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | z * math.sqrt(f32(f64(x) * x + f64(y) * y)) | 51 | return z * math.sqrt(f32(f64(x) * x + f64(y) * y)); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | fn sq(hi: &f64, lo: &f64, x: f64) { | 54 | fn sq(hi: &f64, lo: &f64, x: f64) { |
| ... | @@ -109,7 +109,7 @@ fn hypot64(x: f64, y: f64) -> f64 { | ... | @@ -109,7 +109,7 @@ fn hypot64(x: f64, y: f64) -> f64 { |
| 109 | sq(&hx, &lx, x); | 109 | sq(&hx, &lx, x); |
| 110 | sq(&hy, &ly, y); | 110 | sq(&hy, &ly, y); |
| 111 | 111 | ||
| 112 | z * math.sqrt(ly + lx + hy + hx) | 112 | return z * math.sqrt(ly + lx + hy + hx); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | test "math.hypot" { | 115 | test "math.hypot" { |
std/math/ilogb.zig+6-6| ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; |
| 9 | 9 | ||
| 10 | pub fn ilogb(x: var) -> i32 { | 10 | pub fn ilogb(x: var) -> i32 { |
| 11 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
| 12 | switch (T) { | 12 | return switch (T) { |
| 13 | f32 => @inlineCall(ilogb32, x), | 13 | f32 => ilogb32(x), |
| 14 | f64 => @inlineCall(ilogb64, x), | 14 | f64 => ilogb64(x), |
| 15 | else => @compileError("ilogb not implemented for " ++ @typeName(T)), | 15 | else => @compileError("ilogb not implemented for " ++ @typeName(T)), |
| 16 | } | 16 | }; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | // NOTE: Should these be exposed publically? | 19 | // NOTE: Should these be exposed publically? |
| ... | @@ -53,7 +53,7 @@ fn ilogb32(x: f32) -> i32 { | ... | @@ -53,7 +53,7 @@ fn ilogb32(x: f32) -> i32 { |
| 53 | } | 53 | } |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | e - 0x7F | 56 | return e - 0x7F; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | fn ilogb64(x: f64) -> i32 { | 59 | fn ilogb64(x: f64) -> i32 { |
| ... | @@ -88,7 +88,7 @@ fn ilogb64(x: f64) -> i32 { | ... | @@ -88,7 +88,7 @@ fn ilogb64(x: f64) -> i32 { |
| 88 | } | 88 | } |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | e - 0x3FF | 91 | return e - 0x3FF; |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | test "math.ilogb" { | 94 | test "math.ilogb" { |
std/math/index.zig+33-14| ... | @@ -36,7 +36,7 @@ pub const inf = @import("inf.zig").inf; | ... | @@ -36,7 +36,7 @@ pub const inf = @import("inf.zig").inf; |
| 36 | 36 | ||
| 37 | pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) -> bool { | 37 | pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) -> bool { |
| 38 | assert(@typeId(T) == TypeId.Float); | 38 | assert(@typeId(T) == TypeId.Float); |
| 39 | fabs(x - y) < epsilon | 39 | return fabs(x - y) < epsilon; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | // TODO: Hide the following in an internal module. | 42 | // TODO: Hide the following in an internal module. |
| ... | @@ -174,14 +174,8 @@ test "math" { | ... | @@ -174,14 +174,8 @@ test "math" { |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | 176 | ||
| 177 | pub const Cmp = enum { | ||
| 178 | Less, | ||
| 179 | Equal, | ||
| 180 | Greater, | ||
| 181 | }; | ||
| 182 | |||
| 183 | pub fn min(x: var, y: var) -> @typeOf(x + y) { | 177 | pub fn min(x: var, y: var) -> @typeOf(x + y) { |
| 184 | if (x < y) x else y | 178 | return if (x < y) x else y; |
| 185 | } | 179 | } |
| 186 | 180 | ||
| 187 | test "math.min" { | 181 | test "math.min" { |
| ... | @@ -189,7 +183,7 @@ test "math.min" { | ... | @@ -189,7 +183,7 @@ test "math.min" { |
| 189 | } | 183 | } |
| 190 | 184 | ||
| 191 | pub fn max(x: var, y: var) -> @typeOf(x + y) { | 185 | pub fn max(x: var, y: var) -> @typeOf(x + y) { |
| 192 | if (x > y) x else y | 186 | return if (x > y) x else y; |
| 193 | } | 187 | } |
| 194 | 188 | ||
| 195 | test "math.max" { | 189 | test "math.max" { |
| ... | @@ -199,19 +193,19 @@ test "math.max" { | ... | @@ -199,19 +193,19 @@ test "math.max" { |
| 199 | error Overflow; | 193 | error Overflow; |
| 200 | pub fn mul(comptime T: type, a: T, b: T) -> %T { | 194 | pub fn mul(comptime T: type, a: T, b: T) -> %T { |
| 201 | var answer: T = undefined; | 195 | var answer: T = undefined; |
| 202 | if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer | 196 | return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer; |
| 203 | } | 197 | } |
| 204 | 198 | ||
| 205 | error Overflow; | 199 | error Overflow; |
| 206 | pub fn add(comptime T: type, a: T, b: T) -> %T { | 200 | pub fn add(comptime T: type, a: T, b: T) -> %T { |
| 207 | var answer: T = undefined; | 201 | var answer: T = undefined; |
| 208 | if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer | 202 | return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; |
| 209 | } | 203 | } |
| 210 | 204 | ||
| 211 | error Overflow; | 205 | error Overflow; |
| 212 | pub fn sub(comptime T: type, a: T, b: T) -> %T { | 206 | pub fn sub(comptime T: type, a: T, b: T) -> %T { |
| 213 | var answer: T = undefined; | 207 | var answer: T = undefined; |
| 214 | if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer | 208 | return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer; |
| 215 | } | 209 | } |
| 216 | 210 | ||
| 217 | pub fn negate(x: var) -> %@typeOf(x) { | 211 | pub fn negate(x: var) -> %@typeOf(x) { |
| ... | @@ -221,7 +215,7 @@ pub fn negate(x: var) -> %@typeOf(x) { | ... | @@ -221,7 +215,7 @@ pub fn negate(x: var) -> %@typeOf(x) { |
| 221 | error Overflow; | 215 | error Overflow; |
| 222 | pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) -> %T { | 216 | pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) -> %T { |
| 223 | var answer: T = undefined; | 217 | var answer: T = undefined; |
| 224 | if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer | 218 | return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer; |
| 225 | } | 219 | } |
| 226 | 220 | ||
| 227 | /// Shifts left. Overflowed bits are truncated. | 221 | /// Shifts left. Overflowed bits are truncated. |
| ... | @@ -273,7 +267,7 @@ test "math.shr" { | ... | @@ -273,7 +267,7 @@ test "math.shr" { |
| 273 | } | 267 | } |
| 274 | 268 | ||
| 275 | pub fn Log2Int(comptime T: type) -> type { | 269 | pub fn Log2Int(comptime T: type) -> type { |
| 276 | @IntType(false, log2(T.bit_count)) | 270 | return @IntType(false, log2(T.bit_count)); |
| 277 | } | 271 | } |
| 278 | 272 | ||
| 279 | test "math overflow functions" { | 273 | test "math overflow functions" { |
| ... | @@ -522,3 +516,28 @@ pub fn cast(comptime T: type, x: var) -> %T { | ... | @@ -522,3 +516,28 @@ pub fn cast(comptime T: type, x: var) -> %T { |
| 522 | return T(x); | 516 | return T(x); |
| 523 | } | 517 | } |
| 524 | } | 518 | } |
| 519 | |||
| 520 | pub fn floorPowerOfTwo(comptime T: type, value: T) -> T { | ||
| 521 | var x = value; | ||
| 522 | |||
| 523 | comptime var i = 1; | ||
| 524 | inline while(T.bit_count > i) : (i *= 2) { | ||
| 525 | x |= (x >> i); | ||
| 526 | } | ||
| 527 | |||
| 528 | return x - (x >> 1); | ||
| 529 | } | ||
| 530 | |||
| 531 | test "math.floorPowerOfTwo" { | ||
| 532 | testFloorPowerOfTwo(); | ||
| 533 | comptime testFloorPowerOfTwo(); | ||
| 534 | } | ||
| 535 | |||
| 536 | fn testFloorPowerOfTwo() { | ||
| 537 | assert(floorPowerOfTwo(u32, 63) == 32); | ||
| 538 | assert(floorPowerOfTwo(u32, 64) == 64); | ||
| 539 | assert(floorPowerOfTwo(u32, 65) == 64); | ||
| 540 | assert(floorPowerOfTwo(u4, 7) == 4); | ||
| 541 | assert(floorPowerOfTwo(u4, 8) == 8); | ||
| 542 | assert(floorPowerOfTwo(u4, 9) == 8); | ||
| 543 | } |
std/math/inf.zig+2-2| ... | @@ -2,9 +2,9 @@ const math = @import("index.zig"); | ... | @@ -2,9 +2,9 @@ const math = @import("index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const assert = @import("../debug.zig").assert; |
| 3 | 3 | ||
| 4 | pub fn inf(comptime T: type) -> T { | 4 | pub fn inf(comptime T: type) -> T { |
| 5 | switch (T) { | 5 | return switch (T) { |
| 6 | f32 => @bitCast(f32, math.inf_u32), | 6 | f32 => @bitCast(f32, math.inf_u32), |
| 7 | f64 => @bitCast(f64, math.inf_u64), | 7 | f64 => @bitCast(f64, math.inf_u64), |
| 8 | else => @compileError("inf not implemented for " ++ @typeName(T)), | 8 | else => @compileError("inf not implemented for " ++ @typeName(T)), |
| 9 | } | 9 | }; |
| 10 | } | 10 | } |
std/math/isfinite.zig+2-2| ... | @@ -6,11 +6,11 @@ pub fn isFinite(x: var) -> bool { | ... | @@ -6,11 +6,11 @@ pub fn isFinite(x: var) -> bool { |
| 6 | switch (T) { | 6 | switch (T) { |
| 7 | f32 => { | 7 | f32 => { |
| 8 | const bits = @bitCast(u32, x); | 8 | const bits = @bitCast(u32, x); |
| 9 | bits & 0x7FFFFFFF < 0x7F800000 | 9 | return bits & 0x7FFFFFFF < 0x7F800000; |
| 10 | }, | 10 | }, |
| 11 | f64 => { | 11 | f64 => { |
| 12 | const bits = @bitCast(u64, x); | 12 | const bits = @bitCast(u64, x); |
| 13 | bits & (@maxValue(u64) >> 1) < (0x7FF << 52) | 13 | return bits & (@maxValue(u64) >> 1) < (0x7FF << 52); |
| 14 | }, | 14 | }, |
| 15 | else => { | 15 | else => { |
| 16 | @compileError("isFinite not implemented for " ++ @typeName(T)); | 16 | @compileError("isFinite not implemented for " ++ @typeName(T)); |
std/math/isinf.zig+6-6| ... | @@ -6,11 +6,11 @@ pub fn isInf(x: var) -> bool { | ... | @@ -6,11 +6,11 @@ pub fn isInf(x: var) -> bool { |
| 6 | switch (T) { | 6 | switch (T) { |
| 7 | f32 => { | 7 | f32 => { |
| 8 | const bits = @bitCast(u32, x); | 8 | const bits = @bitCast(u32, x); |
| 9 | bits & 0x7FFFFFFF == 0x7F800000 | 9 | return bits & 0x7FFFFFFF == 0x7F800000; |
| 10 | }, | 10 | }, |
| 11 | f64 => { | 11 | f64 => { |
| 12 | const bits = @bitCast(u64, x); | 12 | const bits = @bitCast(u64, x); |
| 13 | bits & (@maxValue(u64) >> 1) == (0x7FF << 52) | 13 | return bits & (@maxValue(u64) >> 1) == (0x7FF << 52); |
| 14 | }, | 14 | }, |
| 15 | else => { | 15 | else => { |
| 16 | @compileError("isInf not implemented for " ++ @typeName(T)); | 16 | @compileError("isInf not implemented for " ++ @typeName(T)); |
| ... | @@ -22,10 +22,10 @@ pub fn isPositiveInf(x: var) -> bool { | ... | @@ -22,10 +22,10 @@ pub fn isPositiveInf(x: var) -> bool { |
| 22 | const T = @typeOf(x); | 22 | const T = @typeOf(x); |
| 23 | switch (T) { | 23 | switch (T) { |
| 24 | f32 => { | 24 | f32 => { |
| 25 | @bitCast(u32, x) == 0x7F800000 | 25 | return @bitCast(u32, x) == 0x7F800000; |
| 26 | }, | 26 | }, |
| 27 | f64 => { | 27 | f64 => { |
| 28 | @bitCast(u64, x) == 0x7FF << 52 | 28 | return @bitCast(u64, x) == 0x7FF << 52; |
| 29 | }, | 29 | }, |
| 30 | else => { | 30 | else => { |
| 31 | @compileError("isPositiveInf not implemented for " ++ @typeName(T)); | 31 | @compileError("isPositiveInf not implemented for " ++ @typeName(T)); |
| ... | @@ -37,10 +37,10 @@ pub fn isNegativeInf(x: var) -> bool { | ... | @@ -37,10 +37,10 @@ pub fn isNegativeInf(x: var) -> bool { |
| 37 | const T = @typeOf(x); | 37 | const T = @typeOf(x); |
| 38 | switch (T) { | 38 | switch (T) { |
| 39 | f32 => { | 39 | f32 => { |
| 40 | @bitCast(u32, x) == 0xFF800000 | 40 | return @bitCast(u32, x) == 0xFF800000; |
| 41 | }, | 41 | }, |
| 42 | f64 => { | 42 | f64 => { |
| 43 | @bitCast(u64, x) == 0xFFF << 52 | 43 | return @bitCast(u64, x) == 0xFFF << 52; |
| 44 | }, | 44 | }, |
| 45 | else => { | 45 | else => { |
| 46 | @compileError("isNegativeInf not implemented for " ++ @typeName(T)); | 46 | @compileError("isNegativeInf not implemented for " ++ @typeName(T)); |
std/math/isnan.zig+3-3| ... | @@ -6,11 +6,11 @@ pub fn isNan(x: var) -> bool { | ... | @@ -6,11 +6,11 @@ pub fn isNan(x: var) -> bool { |
| 6 | switch (T) { | 6 | switch (T) { |
| 7 | f32 => { | 7 | f32 => { |
| 8 | const bits = @bitCast(u32, x); | 8 | const bits = @bitCast(u32, x); |
| 9 | bits & 0x7FFFFFFF > 0x7F800000 | 9 | return bits & 0x7FFFFFFF > 0x7F800000; |
| 10 | }, | 10 | }, |
| 11 | f64 => { | 11 | f64 => { |
| 12 | const bits = @bitCast(u64, x); | 12 | const bits = @bitCast(u64, x); |
| 13 | (bits & (@maxValue(u64) >> 1)) > (u64(0x7FF) << 52) | 13 | return (bits & (@maxValue(u64) >> 1)) > (u64(0x7FF) << 52); |
| 14 | }, | 14 | }, |
| 15 | else => { | 15 | else => { |
| 16 | @compileError("isNan not implemented for " ++ @typeName(T)); | 16 | @compileError("isNan not implemented for " ++ @typeName(T)); |
| ... | @@ -21,7 +21,7 @@ pub fn isNan(x: var) -> bool { | ... | @@ -21,7 +21,7 @@ pub fn isNan(x: var) -> bool { |
| 21 | // Note: A signalling nan is identical to a standard right now by may have a different bit | 21 | // Note: A signalling nan is identical to a standard right now by may have a different bit |
| 22 | // representation in the future when required. | 22 | // representation in the future when required. |
| 23 | pub fn isSignalNan(x: var) -> bool { | 23 | pub fn isSignalNan(x: var) -> bool { |
| 24 | isNan(x) | 24 | return isNan(x); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | test "math.isNan" { | 27 | test "math.isNan" { |
std/math/isnormal.zig+2-2| ... | @@ -6,11 +6,11 @@ pub fn isNormal(x: var) -> bool { | ... | @@ -6,11 +6,11 @@ pub fn isNormal(x: var) -> bool { |
| 6 | switch (T) { | 6 | switch (T) { |
| 7 | f32 => { | 7 | f32 => { |
| 8 | const bits = @bitCast(u32, x); | 8 | const bits = @bitCast(u32, x); |
| 9 | (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000 | 9 | return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000; |
| 10 | }, | 10 | }, |
| 11 | f64 => { | 11 | f64 => { |
| 12 | const bits = @bitCast(u64, x); | 12 | const bits = @bitCast(u64, x); |
| 13 | (bits + (1 << 52)) & (@maxValue(u64) >> 1) >= (1 << 53) | 13 | return (bits + (1 << 52)) & (@maxValue(u64) >> 1) >= (1 << 53); |
| 14 | }, | 14 | }, |
| 15 | else => { | 15 | else => { |
| 16 | @compileError("isNormal not implemented for " ++ @typeName(T)); | 16 | @compileError("isNormal not implemented for " ++ @typeName(T)); |
std/math/ln.zig+4-4| ... | @@ -14,7 +14,7 @@ pub fn ln(x: var) -> @typeOf(x) { | ... | @@ -14,7 +14,7 @@ pub fn ln(x: var) -> @typeOf(x) { |
| 14 | const T = @typeOf(x); | 14 | const T = @typeOf(x); |
| 15 | switch (@typeId(T)) { | 15 | switch (@typeId(T)) { |
| 16 | TypeId.FloatLiteral => { | 16 | TypeId.FloatLiteral => { |
| 17 | return @typeOf(1.0)(ln_64(x)) | 17 | return @typeOf(1.0)(ln_64(x)); |
| 18 | }, | 18 | }, |
| 19 | TypeId.Float => { | 19 | TypeId.Float => { |
| 20 | return switch (T) { | 20 | return switch (T) { |
| ... | @@ -84,7 +84,7 @@ pub fn ln_32(x_: f32) -> f32 { | ... | @@ -84,7 +84,7 @@ pub fn ln_32(x_: f32) -> f32 { |
| 84 | const hfsq = 0.5 * f * f; | 84 | const hfsq = 0.5 * f * f; |
| 85 | const dk = f32(k); | 85 | const dk = f32(k); |
| 86 | 86 | ||
| 87 | s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi | 87 | return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | pub fn ln_64(x_: f64) -> f64 { | 90 | pub fn ln_64(x_: f64) -> f64 { |
| ... | @@ -116,7 +116,7 @@ pub fn ln_64(x_: f64) -> f64 { | ... | @@ -116,7 +116,7 @@ pub fn ln_64(x_: f64) -> f64 { |
| 116 | // subnormal, scale x | 116 | // subnormal, scale x |
| 117 | k -= 54; | 117 | k -= 54; |
| 118 | x *= 0x1.0p54; | 118 | x *= 0x1.0p54; |
| 119 | hx = u32(@bitCast(u64, ix) >> 32) | 119 | hx = u32(@bitCast(u64, ix) >> 32); |
| 120 | } | 120 | } |
| 121 | else if (hx >= 0x7FF00000) { | 121 | else if (hx >= 0x7FF00000) { |
| 122 | return x; | 122 | return x; |
| ... | @@ -142,7 +142,7 @@ pub fn ln_64(x_: f64) -> f64 { | ... | @@ -142,7 +142,7 @@ pub fn ln_64(x_: f64) -> f64 { |
| 142 | const R = t2 + t1; | 142 | const R = t2 + t1; |
| 143 | const dk = f64(k); | 143 | const dk = f64(k); |
| 144 | 144 | ||
| 145 | s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi | 145 | return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | test "math.ln" { | 148 | test "math.ln" { |
std/math/log.zig+1-1| ... | @@ -29,7 +29,7 @@ pub fn log(comptime T: type, base: T, x: T) -> T { | ... | @@ -29,7 +29,7 @@ pub fn log(comptime T: type, base: T, x: T) -> T { |
| 29 | f32 => return f32(math.ln(f64(x)) / math.ln(f64(base))), | 29 | f32 => return f32(math.ln(f64(x)) / math.ln(f64(base))), |
| 30 | f64 => return math.ln(x) / math.ln(f64(base)), | 30 | f64 => return math.ln(x) / math.ln(f64(base)), |
| 31 | else => @compileError("log not implemented for " ++ @typeName(T)), | 31 | else => @compileError("log not implemented for " ++ @typeName(T)), |
| 32 | }; | 32 | } |
| 33 | }, | 33 | }, |
| 34 | 34 | ||
| 35 | else => { | 35 | else => { |
std/math/log10.zig+4-4| ... | @@ -14,7 +14,7 @@ pub fn log10(x: var) -> @typeOf(x) { | ... | @@ -14,7 +14,7 @@ pub fn log10(x: var) -> @typeOf(x) { |
| 14 | const T = @typeOf(x); | 14 | const T = @typeOf(x); |
| 15 | switch (@typeId(T)) { | 15 | switch (@typeId(T)) { |
| 16 | TypeId.FloatLiteral => { | 16 | TypeId.FloatLiteral => { |
| 17 | return @typeOf(1.0)(log10_64(x)) | 17 | return @typeOf(1.0)(log10_64(x)); |
| 18 | }, | 18 | }, |
| 19 | TypeId.Float => { | 19 | TypeId.Float => { |
| 20 | return switch (T) { | 20 | return switch (T) { |
| ... | @@ -90,7 +90,7 @@ pub fn log10_32(x_: f32) -> f32 { | ... | @@ -90,7 +90,7 @@ pub fn log10_32(x_: f32) -> f32 { |
| 90 | const lo = f - hi - hfsq + s * (hfsq + R); | 90 | const lo = f - hi - hfsq + s * (hfsq + R); |
| 91 | const dk = f32(k); | 91 | const dk = f32(k); |
| 92 | 92 | ||
| 93 | dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi | 93 | return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | pub fn log10_64(x_: f64) -> f64 { | 96 | pub fn log10_64(x_: f64) -> f64 { |
| ... | @@ -124,7 +124,7 @@ pub fn log10_64(x_: f64) -> f64 { | ... | @@ -124,7 +124,7 @@ pub fn log10_64(x_: f64) -> f64 { |
| 124 | // subnormal, scale x | 124 | // subnormal, scale x |
| 125 | k -= 54; | 125 | k -= 54; |
| 126 | x *= 0x1.0p54; | 126 | x *= 0x1.0p54; |
| 127 | hx = u32(@bitCast(u64, x) >> 32) | 127 | hx = u32(@bitCast(u64, x) >> 32); |
| 128 | } | 128 | } |
| 129 | else if (hx >= 0x7FF00000) { | 129 | else if (hx >= 0x7FF00000) { |
| 130 | return x; | 130 | return x; |
| ... | @@ -167,7 +167,7 @@ pub fn log10_64(x_: f64) -> f64 { | ... | @@ -167,7 +167,7 @@ pub fn log10_64(x_: f64) -> f64 { |
| 167 | val_lo += (y - ww) + val_hi; | 167 | val_lo += (y - ww) + val_hi; |
| 168 | val_hi = ww; | 168 | val_hi = ww; |
| 169 | 169 | ||
| 170 | val_lo + val_hi | 170 | return val_lo + val_hi; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | test "math.log10" { | 173 | test "math.log10" { |
std/math/log1p.zig+6-6| ... | @@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert; |
| 11 | 11 | ||
| 12 | pub fn log1p(x: var) -> @typeOf(x) { | 12 | pub fn log1p(x: var) -> @typeOf(x) { |
| 13 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
| 14 | switch (T) { | 14 | return switch (T) { |
| 15 | f32 => @inlineCall(log1p_32, x), | 15 | f32 => log1p_32(x), |
| 16 | f64 => @inlineCall(log1p_64, x), | 16 | f64 => log1p_64(x), |
| 17 | else => @compileError("log1p not implemented for " ++ @typeName(T)), | 17 | else => @compileError("log1p not implemented for " ++ @typeName(T)), |
| 18 | } | 18 | }; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | fn log1p_32(x: f32) -> f32 { | 21 | fn log1p_32(x: f32) -> f32 { |
| ... | @@ -91,7 +91,7 @@ fn log1p_32(x: f32) -> f32 { | ... | @@ -91,7 +91,7 @@ fn log1p_32(x: f32) -> f32 { |
| 91 | const hfsq = 0.5 * f * f; | 91 | const hfsq = 0.5 * f * f; |
| 92 | const dk = f32(k); | 92 | const dk = f32(k); |
| 93 | 93 | ||
| 94 | s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi | 94 | return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | fn log1p_64(x: f64) -> f64 { | 97 | fn log1p_64(x: f64) -> f64 { |
| ... | @@ -172,7 +172,7 @@ fn log1p_64(x: f64) -> f64 { | ... | @@ -172,7 +172,7 @@ fn log1p_64(x: f64) -> f64 { |
| 172 | const R = t2 + t1; | 172 | const R = t2 + t1; |
| 173 | const dk = f64(k); | 173 | const dk = f64(k); |
| 174 | 174 | ||
| 175 | s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi | 175 | return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi; |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | test "math.log1p" { | 178 | test "math.log1p" { |
std/math/log2.zig+4-4| ... | @@ -14,7 +14,7 @@ pub fn log2(x: var) -> @typeOf(x) { | ... | @@ -14,7 +14,7 @@ pub fn log2(x: var) -> @typeOf(x) { |
| 14 | const T = @typeOf(x); | 14 | const T = @typeOf(x); |
| 15 | switch (@typeId(T)) { | 15 | switch (@typeId(T)) { |
| 16 | TypeId.FloatLiteral => { | 16 | TypeId.FloatLiteral => { |
| 17 | return @typeOf(1.0)(log2_64(x)) | 17 | return @typeOf(1.0)(log2_64(x)); |
| 18 | }, | 18 | }, |
| 19 | TypeId.Float => { | 19 | TypeId.Float => { |
| 20 | return switch (T) { | 20 | return switch (T) { |
| ... | @@ -26,7 +26,7 @@ pub fn log2(x: var) -> @typeOf(x) { | ... | @@ -26,7 +26,7 @@ pub fn log2(x: var) -> @typeOf(x) { |
| 26 | TypeId.IntLiteral => comptime { | 26 | TypeId.IntLiteral => comptime { |
| 27 | var result = 0; | 27 | var result = 0; |
| 28 | var x_shifted = x; | 28 | var x_shifted = x; |
| 29 | while ({x_shifted >>= 1; x_shifted != 0}) : (result += 1) {} | 29 | while (b: {x_shifted >>= 1; break :b x_shifted != 0;}) : (result += 1) {} |
| 30 | return result; | 30 | return result; |
| 31 | }, | 31 | }, |
| 32 | TypeId.Int => { | 32 | TypeId.Int => { |
| ... | @@ -94,7 +94,7 @@ pub fn log2_32(x_: f32) -> f32 { | ... | @@ -94,7 +94,7 @@ pub fn log2_32(x_: f32) -> f32 { |
| 94 | u &= 0xFFFFF000; | 94 | u &= 0xFFFFF000; |
| 95 | hi = @bitCast(f32, u); | 95 | hi = @bitCast(f32, u); |
| 96 | const lo = f - hi - hfsq + s * (hfsq + R); | 96 | const lo = f - hi - hfsq + s * (hfsq + R); |
| 97 | (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k) | 97 | return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | pub fn log2_64(x_: f64) -> f64 { | 100 | pub fn log2_64(x_: f64) -> f64 { |
| ... | @@ -165,7 +165,7 @@ pub fn log2_64(x_: f64) -> f64 { | ... | @@ -165,7 +165,7 @@ pub fn log2_64(x_: f64) -> f64 { |
| 165 | val_lo += (y - ww) + val_hi; | 165 | val_lo += (y - ww) + val_hi; |
| 166 | val_hi = ww; | 166 | val_hi = ww; |
| 167 | 167 | ||
| 168 | val_lo + val_hi | 168 | return val_lo + val_hi; |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | test "math.log2" { | 171 | test "math.log2" { |
std/math/modf.zig+8-8| ... | @@ -7,21 +7,21 @@ const math = @import("index.zig"); | ... | @@ -7,21 +7,21 @@ const math = @import("index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const assert = @import("../debug.zig").assert; |
| 8 | 8 | ||
| 9 | fn modf_result(comptime T: type) -> type { | 9 | fn modf_result(comptime T: type) -> type { |
| 10 | struct { | 10 | return struct { |
| 11 | fpart: T, | 11 | fpart: T, |
| 12 | ipart: T, | 12 | ipart: T, |
| 13 | } | 13 | }; |
| 14 | } | 14 | } |
| 15 | pub const modf32_result = modf_result(f32); | 15 | pub const modf32_result = modf_result(f32); |
| 16 | pub const modf64_result = modf_result(f64); | 16 | pub const modf64_result = modf_result(f64); |
| 17 | 17 | ||
| 18 | pub fn modf(x: var) -> modf_result(@typeOf(x)) { | 18 | pub fn modf(x: var) -> modf_result(@typeOf(x)) { |
| 19 | const T = @typeOf(x); | 19 | const T = @typeOf(x); |
| 20 | switch (T) { | 20 | return switch (T) { |
| 21 | f32 => @inlineCall(modf32, x), | 21 | f32 => modf32(x), |
| 22 | f64 => @inlineCall(modf64, x), | 22 | f64 => modf64(x), |
| 23 | else => @compileError("modf not implemented for " ++ @typeName(T)), | 23 | else => @compileError("modf not implemented for " ++ @typeName(T)), |
| 24 | } | 24 | }; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | fn modf32(x: f32) -> modf32_result { | 27 | fn modf32(x: f32) -> modf32_result { |
| ... | @@ -66,7 +66,7 @@ fn modf32(x: f32) -> modf32_result { | ... | @@ -66,7 +66,7 @@ fn modf32(x: f32) -> modf32_result { |
| 66 | const uf = @bitCast(f32, u & ~mask); | 66 | const uf = @bitCast(f32, u & ~mask); |
| 67 | result.ipart = uf; | 67 | result.ipart = uf; |
| 68 | result.fpart = x - uf; | 68 | result.fpart = x - uf; |
| 69 | result | 69 | return result; |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | fn modf64(x: f64) -> modf64_result { | 72 | fn modf64(x: f64) -> modf64_result { |
| ... | @@ -110,7 +110,7 @@ fn modf64(x: f64) -> modf64_result { | ... | @@ -110,7 +110,7 @@ fn modf64(x: f64) -> modf64_result { |
| 110 | const uf = @bitCast(f64, u & ~mask); | 110 | const uf = @bitCast(f64, u & ~mask); |
| 111 | result.ipart = uf; | 111 | result.ipart = uf; |
| 112 | result.fpart = x - uf; | 112 | result.fpart = x - uf; |
| 113 | result | 113 | return result; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | test "math.modf" { | 116 | test "math.modf" { |
std/math/nan.zig+4-4| ... | @@ -1,19 +1,19 @@ | ... | @@ -1,19 +1,19 @@ |
| 1 | const math = @import("index.zig"); | 1 | const math = @import("index.zig"); |
| 2 | 2 | ||
| 3 | pub fn nan(comptime T: type) -> T { | 3 | pub fn nan(comptime T: type) -> T { |
| 4 | switch (T) { | 4 | return switch (T) { |
| 5 | f32 => @bitCast(f32, math.nan_u32), | 5 | f32 => @bitCast(f32, math.nan_u32), |
| 6 | f64 => @bitCast(f64, math.nan_u64), | 6 | f64 => @bitCast(f64, math.nan_u64), |
| 7 | else => @compileError("nan not implemented for " ++ @typeName(T)), | 7 | else => @compileError("nan not implemented for " ++ @typeName(T)), |
| 8 | } | 8 | }; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | // Note: A signalling nan is identical to a standard right now by may have a different bit | 11 | // Note: A signalling nan is identical to a standard right now by may have a different bit |
| 12 | // representation in the future when required. | 12 | // representation in the future when required. |
| 13 | pub fn snan(comptime T: type) -> T { | 13 | pub fn snan(comptime T: type) -> T { |
| 14 | switch (T) { | 14 | return switch (T) { |
| 15 | f32 => @bitCast(f32, math.nan_u32), | 15 | f32 => @bitCast(f32, math.nan_u32), |
| 16 | f64 => @bitCast(f64, math.nan_u64), | 16 | f64 => @bitCast(f64, math.nan_u64), |
| 17 | else => @compileError("snan not implemented for " ++ @typeName(T)), | 17 | else => @compileError("snan not implemented for " ++ @typeName(T)), |
| 18 | } | 18 | }; |
| 19 | } | 19 | } |
std/math/pow.zig+2-2| ... | @@ -166,12 +166,12 @@ pub fn pow(comptime T: type, x: T, y: T) -> T { | ... | @@ -166,12 +166,12 @@ pub fn pow(comptime T: type, x: T, y: T) -> T { |
| 166 | ae = -ae; | 166 | ae = -ae; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | math.scalbn(a1, ae) | 169 | return math.scalbn(a1, ae); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | fn isOddInteger(x: f64) -> bool { | 172 | fn isOddInteger(x: f64) -> bool { |
| 173 | const r = math.modf(x); | 173 | const r = math.modf(x); |
| 174 | r.fpart == 0.0 and i64(r.ipart) & 1 == 1 | 174 | return r.fpart == 0.0 and i64(r.ipart) & 1 == 1; |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | test "math.pow" { | 177 | test "math.pow" { |
std/math/round.zig+8-8| ... | @@ -10,11 +10,11 @@ const math = @import("index.zig"); | ... | @@ -10,11 +10,11 @@ const math = @import("index.zig"); |
| 10 | 10 | ||
| 11 | pub fn round(x: var) -> @typeOf(x) { | 11 | pub fn round(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
| 13 | switch (T) { | 13 | return switch (T) { |
| 14 | f32 => @inlineCall(round32, x), | 14 | f32 => round32(x), |
| 15 | f64 => @inlineCall(round64, x), | 15 | f64 => round64(x), |
| 16 | else => @compileError("round not implemented for " ++ @typeName(T)), | 16 | else => @compileError("round not implemented for " ++ @typeName(T)), |
| 17 | } | 17 | }; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | fn round32(x_: f32) -> f32 { | 20 | fn round32(x_: f32) -> f32 { |
| ... | @@ -48,9 +48,9 @@ fn round32(x_: f32) -> f32 { | ... | @@ -48,9 +48,9 @@ fn round32(x_: f32) -> f32 { |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | if (u >> 31 != 0) { | 50 | if (u >> 31 != 0) { |
| 51 | -y | 51 | return -y; |
| 52 | } else { | 52 | } else { |
| 53 | y | 53 | return y; |
| 54 | } | 54 | } |
| 55 | } | 55 | } |
| 56 | 56 | ||
| ... | @@ -85,9 +85,9 @@ fn round64(x_: f64) -> f64 { | ... | @@ -85,9 +85,9 @@ fn round64(x_: f64) -> f64 { |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | if (u >> 63 != 0) { | 87 | if (u >> 63 != 0) { |
| 88 | -y | 88 | return -y; |
| 89 | } else { | 89 | } else { |
| 90 | y | 90 | return y; |
| 91 | } | 91 | } |
| 92 | } | 92 | } |
| 93 | 93 |
std/math/scalbn.zig+6-6| ... | @@ -3,11 +3,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -3,11 +3,11 @@ const assert = @import("../debug.zig").assert; |
| 3 | 3 | ||
| 4 | pub fn scalbn(x: var, n: i32) -> @typeOf(x) { | 4 | pub fn scalbn(x: var, n: i32) -> @typeOf(x) { |
| 5 | const T = @typeOf(x); | 5 | const T = @typeOf(x); |
| 6 | switch (T) { | 6 | return switch (T) { |
| 7 | f32 => @inlineCall(scalbn32, x, n), | 7 | f32 => scalbn32(x, n), |
| 8 | f64 => @inlineCall(scalbn64, x, n), | 8 | f64 => scalbn64(x, n), |
| 9 | else => @compileError("scalbn not implemented for " ++ @typeName(T)), | 9 | else => @compileError("scalbn not implemented for " ++ @typeName(T)), |
| 10 | } | 10 | }; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | fn scalbn32(x: f32, n_: i32) -> f32 { | 13 | fn scalbn32(x: f32, n_: i32) -> f32 { |
| ... | @@ -37,7 +37,7 @@ fn scalbn32(x: f32, n_: i32) -> f32 { | ... | @@ -37,7 +37,7 @@ fn scalbn32(x: f32, n_: i32) -> f32 { |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | const u = u32(n +% 0x7F) << 23; | 39 | const u = u32(n +% 0x7F) << 23; |
| 40 | y * @bitCast(f32, u) | 40 | return y * @bitCast(f32, u); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | fn scalbn64(x: f64, n_: i32) -> f64 { | 43 | fn scalbn64(x: f64, n_: i32) -> f64 { |
| ... | @@ -67,7 +67,7 @@ fn scalbn64(x: f64, n_: i32) -> f64 { | ... | @@ -67,7 +67,7 @@ fn scalbn64(x: f64, n_: i32) -> f64 { |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | const u = u64(n +% 0x3FF) << 52; | 69 | const u = u64(n +% 0x3FF) << 52; |
| 70 | y * @bitCast(f64, u) | 70 | return y * @bitCast(f64, u); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | test "math.scalbn" { | 73 | test "math.scalbn" { |
std/math/signbit.zig+6-6| ... | @@ -3,21 +3,21 @@ const assert = @import("../debug.zig").assert; | ... | @@ -3,21 +3,21 @@ const assert = @import("../debug.zig").assert; |
| 3 | 3 | ||
| 4 | pub fn signbit(x: var) -> bool { | 4 | pub fn signbit(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 5 | const T = @typeOf(x); |
| 6 | switch (T) { | 6 | return switch (T) { |
| 7 | f32 => @inlineCall(signbit32, x), | 7 | f32 => signbit32(x), |
| 8 | f64 => @inlineCall(signbit64, x), | 8 | f64 => signbit64(x), |
| 9 | else => @compileError("signbit not implemented for " ++ @typeName(T)), | 9 | else => @compileError("signbit not implemented for " ++ @typeName(T)), |
| 10 | } | 10 | }; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | fn signbit32(x: f32) -> bool { | 13 | fn signbit32(x: f32) -> bool { |
| 14 | const bits = @bitCast(u32, x); | 14 | const bits = @bitCast(u32, x); |
| 15 | bits >> 31 != 0 | 15 | return bits >> 31 != 0; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | fn signbit64(x: f64) -> bool { | 18 | fn signbit64(x: f64) -> bool { |
| 19 | const bits = @bitCast(u64, x); | 19 | const bits = @bitCast(u64, x); |
| 20 | bits >> 63 != 0 | 20 | return bits >> 63 != 0; |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | test "math.signbit" { | 23 | test "math.signbit" { |
std/math/sin.zig+15-15| ... | @@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert; |
| 10 | 10 | ||
| 11 | pub fn sin(x: var) -> @typeOf(x) { | 11 | pub fn sin(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
| 13 | switch (T) { | 13 | return switch (T) { |
| 14 | f32 => @inlineCall(sin32, x), | 14 | f32 => sin32(x), |
| 15 | f64 => @inlineCall(sin64, x), | 15 | f64 => sin64(x), |
| 16 | else => @compileError("sin not implemented for " ++ @typeName(T)), | 16 | else => @compileError("sin not implemented for " ++ @typeName(T)), |
| 17 | } | 17 | }; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | // sin polynomial coefficients | 20 | // sin polynomial coefficients |
| ... | @@ -75,18 +75,18 @@ fn sin32(x_: f32) -> f32 { | ... | @@ -75,18 +75,18 @@ fn sin32(x_: f32) -> f32 { |
| 75 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | 75 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; |
| 76 | const w = z * z; | 76 | const w = z * z; |
| 77 | 77 | ||
| 78 | const r = { | 78 | const r = r: { |
| 79 | if (j == 1 or j == 2) { | 79 | if (j == 1 or j == 2) { |
| 80 | 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))) | 80 | break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); |
| 81 | } else { | 81 | } else { |
| 82 | z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))) | 82 | break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); |
| 83 | } | 83 | } |
| 84 | }; | 84 | }; |
| 85 | 85 | ||
| 86 | if (sign) { | 86 | if (sign) { |
| 87 | -r | 87 | return -r; |
| 88 | } else { | 88 | } else { |
| 89 | r | 89 | return r; |
| 90 | } | 90 | } |
| 91 | } | 91 | } |
| 92 | 92 | ||
| ... | @@ -127,25 +127,25 @@ fn sin64(x_: f64) -> f64 { | ... | @@ -127,25 +127,25 @@ fn sin64(x_: f64) -> f64 { |
| 127 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | 127 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; |
| 128 | const w = z * z; | 128 | const w = z * z; |
| 129 | 129 | ||
| 130 | const r = { | 130 | const r = r: { |
| 131 | if (j == 1 or j == 2) { | 131 | if (j == 1 or j == 2) { |
| 132 | 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))) | 132 | break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); |
| 133 | } else { | 133 | } else { |
| 134 | z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))) | 134 | break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); |
| 135 | } | 135 | } |
| 136 | }; | 136 | }; |
| 137 | 137 | ||
| 138 | if (sign) { | 138 | if (sign) { |
| 139 | -r | 139 | return -r; |
| 140 | } else { | 140 | } else { |
| 141 | r | 141 | return r; |
| 142 | } | 142 | } |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | test "math.sin" { | 145 | test "math.sin" { |
| 146 | assert(sin(f32(0.0)) == sin32(0.0)); | 146 | assert(sin(f32(0.0)) == sin32(0.0)); |
| 147 | assert(sin(f64(0.0)) == sin64(0.0)); | 147 | assert(sin(f64(0.0)) == sin64(0.0)); |
| 148 | assert(comptime {math.sin(f64(2))} == math.sin(f64(2))); | 148 | assert(comptime (math.sin(f64(2))) == math.sin(f64(2))); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | test "math.sin32" { | 151 | test "math.sin32" { |
std/math/sinh.zig+6-6| ... | @@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2; | ... | @@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2; |
| 11 | 11 | ||
| 12 | pub fn sinh(x: var) -> @typeOf(x) { | 12 | pub fn sinh(x: var) -> @typeOf(x) { |
| 13 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
| 14 | switch (T) { | 14 | return switch (T) { |
| 15 | f32 => @inlineCall(sinh32, x), | 15 | f32 => sinh32(x), |
| 16 | f64 => @inlineCall(sinh64, x), | 16 | f64 => sinh64(x), |
| 17 | else => @compileError("sinh not implemented for " ++ @typeName(T)), | 17 | else => @compileError("sinh not implemented for " ++ @typeName(T)), |
| 18 | } | 18 | }; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | // sinh(x) = (exp(x) - 1 / exp(x)) / 2 | 21 | // sinh(x) = (exp(x) - 1 / exp(x)) / 2 |
| ... | @@ -49,7 +49,7 @@ fn sinh32(x: f32) -> f32 { | ... | @@ -49,7 +49,7 @@ fn sinh32(x: f32) -> f32 { |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | // |x| > log(FLT_MAX) or nan | 51 | // |x| > log(FLT_MAX) or nan |
| 52 | 2 * h * expo2(ax) | 52 | return 2 * h * expo2(ax); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | fn sinh64(x: f64) -> f64 { | 55 | fn sinh64(x: f64) -> f64 { |
| ... | @@ -83,7 +83,7 @@ fn sinh64(x: f64) -> f64 { | ... | @@ -83,7 +83,7 @@ fn sinh64(x: f64) -> f64 { |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | // |x| > log(DBL_MAX) or nan | 85 | // |x| > log(DBL_MAX) or nan |
| 86 | 2 * h * expo2(ax) | 86 | return 2 * h * expo2(ax); |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | test "math.sinh" { | 89 | test "math.sinh" { |
std/math/sqrt.zig+62-8| ... | @@ -7,12 +7,34 @@ | ... | @@ -7,12 +7,34 @@ |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const math = @import("index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const assert = @import("../debug.zig").assert; |
| 10 | const builtin = @import("builtin"); | ||
| 11 | const TypeId = builtin.TypeId; | ||
| 10 | 12 | ||
| 11 | pub fn sqrt(x: var) -> @typeOf(x) { | 13 | pub fn sqrt(x: var) -> (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typeOf(x).bit_count / 2) else @typeOf(x)) { |
| 12 | const T = @typeOf(x); | 14 | const T = @typeOf(x); |
| 13 | switch (T) { | 15 | switch (@typeId(T)) { |
| 14 | f32 => @inlineCall(sqrt32, x), | 16 | TypeId.FloatLiteral => { |
| 15 | f64 => @inlineCall(sqrt64, x), | 17 | return T(sqrt64(x)); |
| 18 | }, | ||
| 19 | TypeId.Float => { | ||
| 20 | return switch (T) { | ||
| 21 | f32 => sqrt32(x), | ||
| 22 | f64 => sqrt64(x), | ||
| 23 | else => @compileError("sqrt not implemented for " ++ @typeName(T)), | ||
| 24 | }; | ||
| 25 | }, | ||
| 26 | TypeId.IntLiteral => comptime { | ||
| 27 | if (x > @maxValue(u128)) { | ||
| 28 | @compileError("sqrt not implemented for comptime_int greater than 128 bits"); | ||
| 29 | } | ||
| 30 | if (x < 0) { | ||
| 31 | @compileError("sqrt on negative number"); | ||
| 32 | } | ||
| 33 | return T(sqrt_int(u128, x)); | ||
| 34 | }, | ||
| 35 | TypeId.Int => { | ||
| 36 | return sqrt_int(T, x); | ||
| 37 | }, | ||
| 16 | else => @compileError("sqrt not implemented for " ++ @typeName(T)), | 38 | else => @compileError("sqrt not implemented for " ++ @typeName(T)), |
| 17 | } | 39 | } |
| 18 | } | 40 | } |
| ... | @@ -42,7 +64,7 @@ fn sqrt32(x: f32) -> f32 { | ... | @@ -42,7 +64,7 @@ fn sqrt32(x: f32) -> f32 { |
| 42 | // subnormal | 64 | // subnormal |
| 43 | var i: i32 = 0; | 65 | var i: i32 = 0; |
| 44 | while (ix & 0x00800000 == 0) : (i += 1) { | 66 | while (ix & 0x00800000 == 0) : (i += 1) { |
| 45 | ix <<= 1 | 67 | ix <<= 1; |
| 46 | } | 68 | } |
| 47 | m -= i - 1; | 69 | m -= i - 1; |
| 48 | } | 70 | } |
| ... | @@ -90,7 +112,7 @@ fn sqrt32(x: f32) -> f32 { | ... | @@ -90,7 +112,7 @@ fn sqrt32(x: f32) -> f32 { |
| 90 | 112 | ||
| 91 | ix = (q >> 1) + 0x3f000000; | 113 | ix = (q >> 1) + 0x3f000000; |
| 92 | ix += m << 23; | 114 | ix += m << 23; |
| 93 | @bitCast(f32, ix) | 115 | return @bitCast(f32, ix); |
| 94 | } | 116 | } |
| 95 | 117 | ||
| 96 | // NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound | 118 | // NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound |
| ... | @@ -131,7 +153,7 @@ fn sqrt64(x: f64) -> f64 { | ... | @@ -131,7 +153,7 @@ fn sqrt64(x: f64) -> f64 { |
| 131 | // subnormal | 153 | // subnormal |
| 132 | var i: u32 = 0; | 154 | var i: u32 = 0; |
| 133 | while (ix0 & 0x00100000 == 0) : (i += 1) { | 155 | while (ix0 & 0x00100000 == 0) : (i += 1) { |
| 134 | ix0 <<= 1 | 156 | ix0 <<= 1; |
| 135 | } | 157 | } |
| 136 | m -= i32(i) - 1; | 158 | m -= i32(i) - 1; |
| 137 | ix0 |= ix1 >> u5(32 - i); | 159 | ix0 |= ix1 >> u5(32 - i); |
| ... | @@ -223,7 +245,7 @@ fn sqrt64(x: f64) -> f64 { | ... | @@ -223,7 +245,7 @@ fn sqrt64(x: f64) -> f64 { |
| 223 | iix0 = iix0 +% (m << 20); | 245 | iix0 = iix0 +% (m << 20); |
| 224 | 246 | ||
| 225 | const uz = (u64(iix0) << 32) | ix1; | 247 | const uz = (u64(iix0) << 32) | ix1; |
| 226 | @bitCast(f64, uz) | 248 | return @bitCast(f64, uz); |
| 227 | } | 249 | } |
| 228 | 250 | ||
| 229 | test "math.sqrt" { | 251 | test "math.sqrt" { |
| ... | @@ -274,3 +296,35 @@ test "math.sqrt64.special" { | ... | @@ -274,3 +296,35 @@ test "math.sqrt64.special" { |
| 274 | assert(math.isNan(sqrt64(-1.0))); | 296 | assert(math.isNan(sqrt64(-1.0))); |
| 275 | assert(math.isNan(sqrt64(math.nan(f64)))); | 297 | assert(math.isNan(sqrt64(math.nan(f64)))); |
| 276 | } | 298 | } |
| 299 | |||
| 300 | fn sqrt_int(comptime T: type, value: T) -> @IntType(false, T.bit_count / 2) { | ||
| 301 | var op = value; | ||
| 302 | var res: T = 0; | ||
| 303 | var one: T = 1 << (T.bit_count - 2); | ||
| 304 | |||
| 305 | // "one" starts at the highest power of four <= than the argument. | ||
| 306 | while (one > op) { | ||
| 307 | one >>= 2; | ||
| 308 | } | ||
| 309 | |||
| 310 | while (one != 0) { | ||
| 311 | if (op >= res + one) { | ||
| 312 | op -= res + one; | ||
| 313 | res += 2 * one; | ||
| 314 | } | ||
| 315 | res >>= 1; | ||
| 316 | one >>= 2; | ||
| 317 | } | ||
| 318 | |||
| 319 | const ResultType = @IntType(false, T.bit_count / 2); | ||
| 320 | return ResultType(res); | ||
| 321 | } | ||
| 322 | |||
| 323 | test "math.sqrt_int" { | ||
| 324 | assert(sqrt_int(u32, 3) == 1); | ||
| 325 | assert(sqrt_int(u32, 4) == 2); | ||
| 326 | assert(sqrt_int(u32, 5) == 2); | ||
| 327 | assert(sqrt_int(u32, 8) == 2); | ||
| 328 | assert(sqrt_int(u32, 9) == 3); | ||
| 329 | assert(sqrt_int(u32, 10) == 3); | ||
| 330 | } |
std/math/tan.zig+12-12| ... | @@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert; |
| 10 | 10 | ||
| 11 | pub fn tan(x: var) -> @typeOf(x) { | 11 | pub fn tan(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
| 13 | switch (T) { | 13 | return switch (T) { |
| 14 | f32 => @inlineCall(tan32, x), | 14 | f32 => tan32(x), |
| 15 | f64 => @inlineCall(tan64, x), | 15 | f64 => tan64(x), |
| 16 | else => @compileError("tan not implemented for " ++ @typeName(T)), | 16 | else => @compileError("tan not implemented for " ++ @typeName(T)), |
| 17 | } | 17 | }; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | const Tp0 = -1.30936939181383777646E4; | 20 | const Tp0 = -1.30936939181383777646E4; |
| ... | @@ -62,11 +62,11 @@ fn tan32(x_: f32) -> f32 { | ... | @@ -62,11 +62,11 @@ fn tan32(x_: f32) -> f32 { |
| 62 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | 62 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; |
| 63 | const w = z * z; | 63 | const w = z * z; |
| 64 | 64 | ||
| 65 | var r = { | 65 | var r = r: { |
| 66 | if (w > 1e-14) { | 66 | if (w > 1e-14) { |
| 67 | z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)) | 67 | break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)); |
| 68 | } else { | 68 | } else { |
| 69 | z | 69 | break :r z; |
| 70 | } | 70 | } |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| ... | @@ -77,7 +77,7 @@ fn tan32(x_: f32) -> f32 { | ... | @@ -77,7 +77,7 @@ fn tan32(x_: f32) -> f32 { |
| 77 | r = -r; | 77 | r = -r; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | r | 80 | return r; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | fn tan64(x_: f64) -> f64 { | 83 | fn tan64(x_: f64) -> f64 { |
| ... | @@ -111,11 +111,11 @@ fn tan64(x_: f64) -> f64 { | ... | @@ -111,11 +111,11 @@ fn tan64(x_: f64) -> f64 { |
| 111 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | 111 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; |
| 112 | const w = z * z; | 112 | const w = z * z; |
| 113 | 113 | ||
| 114 | var r = { | 114 | var r = r: { |
| 115 | if (w > 1e-14) { | 115 | if (w > 1e-14) { |
| 116 | z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)) | 116 | break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)); |
| 117 | } else { | 117 | } else { |
| 118 | z | 118 | break :r z; |
| 119 | } | 119 | } |
| 120 | }; | 120 | }; |
| 121 | 121 | ||
| ... | @@ -126,7 +126,7 @@ fn tan64(x_: f64) -> f64 { | ... | @@ -126,7 +126,7 @@ fn tan64(x_: f64) -> f64 { |
| 126 | r = -r; | 126 | r = -r; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | r | 129 | return r; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | test "math.tan" { | 132 | test "math.tan" { |
std/math/tanh.zig+8-8| ... | @@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2; | ... | @@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2; |
| 11 | 11 | ||
| 12 | pub fn tanh(x: var) -> @typeOf(x) { | 12 | pub fn tanh(x: var) -> @typeOf(x) { |
| 13 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
| 14 | switch (T) { | 14 | return switch (T) { |
| 15 | f32 => @inlineCall(tanh32, x), | 15 | f32 => tanh32(x), |
| 16 | f64 => @inlineCall(tanh64, x), | 16 | f64 => tanh64(x), |
| 17 | else => @compileError("tanh not implemented for " ++ @typeName(T)), | 17 | else => @compileError("tanh not implemented for " ++ @typeName(T)), |
| 18 | } | 18 | }; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | // tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x)) | 21 | // tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x)) |
| ... | @@ -59,9 +59,9 @@ fn tanh32(x: f32) -> f32 { | ... | @@ -59,9 +59,9 @@ fn tanh32(x: f32) -> f32 { |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | if (u >> 31 != 0) { | 61 | if (u >> 31 != 0) { |
| 62 | -t | 62 | return -t; |
| 63 | } else { | 63 | } else { |
| 64 | t | 64 | return t; |
| 65 | } | 65 | } |
| 66 | } | 66 | } |
| 67 | 67 | ||
| ... | @@ -104,9 +104,9 @@ fn tanh64(x: f64) -> f64 { | ... | @@ -104,9 +104,9 @@ fn tanh64(x: f64) -> f64 { |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | if (u >> 63 != 0) { | 106 | if (u >> 63 != 0) { |
| 107 | -t | 107 | return -t; |
| 108 | } else { | 108 | } else { |
| 109 | t | 109 | return t; |
| 110 | } | 110 | } |
| 111 | } | 111 | } |
| 112 | 112 |
std/math/trunc.zig+8-8| ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; | ... | @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert; |
| 9 | 9 | ||
| 10 | pub fn trunc(x: var) -> @typeOf(x) { | 10 | pub fn trunc(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
| 12 | switch (T) { | 12 | return switch (T) { |
| 13 | f32 => @inlineCall(trunc32, x), | 13 | f32 => trunc32(x), |
| 14 | f64 => @inlineCall(trunc64, x), | 14 | f64 => trunc64(x), |
| 15 | else => @compileError("trunc not implemented for " ++ @typeName(T)), | 15 | else => @compileError("trunc not implemented for " ++ @typeName(T)), |
| 16 | } | 16 | }; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | fn trunc32(x: f32) -> f32 { | 19 | fn trunc32(x: f32) -> f32 { |
| ... | @@ -30,10 +30,10 @@ fn trunc32(x: f32) -> f32 { | ... | @@ -30,10 +30,10 @@ fn trunc32(x: f32) -> f32 { |
| 30 | 30 | ||
| 31 | m = u32(@maxValue(u32)) >> u5(e); | 31 | m = u32(@maxValue(u32)) >> u5(e); |
| 32 | if (u & m == 0) { | 32 | if (u & m == 0) { |
| 33 | x | 33 | return x; |
| 34 | } else { | 34 | } else { |
| 35 | math.forceEval(x + 0x1p120); | 35 | math.forceEval(x + 0x1p120); |
| 36 | @bitCast(f32, u & ~m) | 36 | return @bitCast(f32, u & ~m); |
| 37 | } | 37 | } |
| 38 | } | 38 | } |
| 39 | 39 | ||
| ... | @@ -51,10 +51,10 @@ fn trunc64(x: f64) -> f64 { | ... | @@ -51,10 +51,10 @@ fn trunc64(x: f64) -> f64 { |
| 51 | 51 | ||
| 52 | m = u64(@maxValue(u64)) >> u6(e); | 52 | m = u64(@maxValue(u64)) >> u6(e); |
| 53 | if (u & m == 0) { | 53 | if (u & m == 0) { |
| 54 | x | 54 | return x; |
| 55 | } else { | 55 | } else { |
| 56 | math.forceEval(x + 0x1p120); | 56 | math.forceEval(x + 0x1p120); |
| 57 | @bitCast(f64, u & ~m) | 57 | return @bitCast(f64, u & ~m); |
| 58 | } | 58 | } |
| 59 | } | 59 | } |
| 60 | 60 |
std/mem.zig+149-36| ... | @@ -3,26 +3,31 @@ const assert = debug.assert; | ... | @@ -3,26 +3,31 @@ const assert = debug.assert; |
| 3 | const math = @import("math/index.zig"); | 3 | const math = @import("math/index.zig"); |
| 4 | const builtin = @import("builtin"); | 4 | const builtin = @import("builtin"); |
| 5 | 5 | ||
| 6 | pub const Cmp = math.Cmp; | 6 | error OutOfMemory; |
| 7 | 7 | ||
| 8 | pub const Allocator = struct { | 8 | pub const Allocator = struct { |
| 9 | /// Allocate byte_count bytes and return them in a slice, with the | 9 | /// Allocate byte_count bytes and return them in a slice, with the |
| 10 | /// slicer's pointer aligned at least to alignment bytes. | 10 | /// slice's pointer aligned at least to alignment bytes. |
| 11 | allocFn: fn (self: &Allocator, byte_count: usize, alignment: usize) -> %[]u8, | 11 | /// The returned newly allocated memory is undefined. |
| 12 | allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) -> %[]u8, | ||
| 12 | 13 | ||
| 13 | /// Guaranteed: `old_mem.len` is the same as what was returned from allocFn or reallocFn. | 14 | /// If `new_byte_count > old_mem.len`: |
| 14 | /// Guaranteed: alignment >= alignment of old_mem.ptr | 15 | /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn. |
| 16 | /// * alignment >= alignment of old_mem.ptr | ||
| 15 | /// | 17 | /// |
| 16 | /// If `new_byte_count` is less than or equal to `old_mem.len` this function must | 18 | /// If `new_byte_count <= old_mem.len`: |
| 17 | /// return successfully. | 19 | /// * this function must return successfully. |
| 18 | reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: usize) -> %[]u8, | 20 | /// * alignment <= alignment of old_mem.ptr |
| 21 | /// | ||
| 22 | /// The returned newly allocated memory is undefined. | ||
| 23 | reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) -> %[]u8, | ||
| 19 | 24 | ||
| 20 | /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` | 25 | /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` |
| 21 | freeFn: fn (self: &Allocator, old_mem: []u8), | 26 | freeFn: fn (self: &Allocator, old_mem: []u8), |
| 22 | 27 | ||
| 23 | fn create(self: &Allocator, comptime T: type) -> %&T { | 28 | fn create(self: &Allocator, comptime T: type) -> %&T { |
| 24 | const slice = %return self.alloc(T, 1); | 29 | const slice = %return self.alloc(T, 1); |
| 25 | &slice[0] | 30 | return &slice[0]; |
| 26 | } | 31 | } |
| 27 | 32 | ||
| 28 | fn destroy(self: &Allocator, ptr: var) { | 33 | fn destroy(self: &Allocator, ptr: var) { |
| ... | @@ -30,28 +35,52 @@ pub const Allocator = struct { | ... | @@ -30,28 +35,52 @@ pub const Allocator = struct { |
| 30 | } | 35 | } |
| 31 | 36 | ||
| 32 | fn alloc(self: &Allocator, comptime T: type, n: usize) -> %[]T { | 37 | fn alloc(self: &Allocator, comptime T: type, n: usize) -> %[]T { |
| 38 | return self.alignedAlloc(T, @alignOf(T), n); | ||
| 39 | } | ||
| 40 | |||
| 41 | fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29, | ||
| 42 | n: usize) -> %[]align(alignment) T | ||
| 43 | { | ||
| 33 | const byte_count = %return math.mul(usize, @sizeOf(T), n); | 44 | const byte_count = %return math.mul(usize, @sizeOf(T), n); |
| 34 | const byte_slice = %return self.allocFn(self, byte_count, @alignOf(T)); | 45 | const byte_slice = %return self.allocFn(self, byte_count, alignment); |
| 35 | ([]T)(@alignCast(@alignOf(T), byte_slice)) | 46 | // This loop should get optimized out in ReleaseFast mode |
| 47 | for (byte_slice) |*byte| { | ||
| 48 | *byte = undefined; | ||
| 49 | } | ||
| 50 | return ([]align(alignment) T)(@alignCast(alignment, byte_slice)); | ||
| 36 | } | 51 | } |
| 37 | 52 | ||
| 38 | fn realloc(self: &Allocator, comptime T: type, old_mem: []T, n: usize) -> %[]T { | 53 | fn realloc(self: &Allocator, comptime T: type, old_mem: []T, n: usize) -> %[]T { |
| 54 | return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n); | ||
| 55 | } | ||
| 56 | |||
| 57 | fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29, | ||
| 58 | old_mem: []align(alignment) T, n: usize) -> %[]align(alignment) T | ||
| 59 | { | ||
| 39 | if (old_mem.len == 0) { | 60 | if (old_mem.len == 0) { |
| 40 | return self.alloc(T, n); | 61 | return self.alloc(T, n); |
| 41 | } | 62 | } |
| 42 | 63 | ||
| 43 | // Assert that old_mem.ptr is properly aligned. | 64 | const old_byte_slice = ([]u8)(old_mem); |
| 44 | const aligned_old_mem = @alignCast(@alignOf(T), old_mem); | ||
| 45 | |||
| 46 | const byte_count = %return math.mul(usize, @sizeOf(T), n); | 65 | const byte_count = %return math.mul(usize, @sizeOf(T), n); |
| 47 | const byte_slice = %return self.reallocFn(self, ([]u8)(aligned_old_mem), byte_count, @alignOf(T)); | 66 | const byte_slice = %return self.reallocFn(self, old_byte_slice, byte_count, alignment); |
| 48 | return ([]T)(@alignCast(@alignOf(T), byte_slice)); | 67 | // This loop should get optimized out in ReleaseFast mode |
| 68 | for (byte_slice[old_byte_slice.len..]) |*byte| { | ||
| 69 | *byte = undefined; | ||
| 70 | } | ||
| 71 | return ([]T)(@alignCast(alignment, byte_slice)); | ||
| 49 | } | 72 | } |
| 50 | 73 | ||
| 51 | /// Reallocate, but `n` must be less than or equal to `old_mem.len`. | 74 | /// Reallocate, but `n` must be less than or equal to `old_mem.len`. |
| 52 | /// Unlike `realloc`, this function cannot fail. | 75 | /// Unlike `realloc`, this function cannot fail. |
| 53 | /// Shrinking to 0 is the same as calling `free`. | 76 | /// Shrinking to 0 is the same as calling `free`. |
| 54 | fn shrink(self: &Allocator, comptime T: type, old_mem: []T, n: usize) -> []T { | 77 | fn shrink(self: &Allocator, comptime T: type, old_mem: []T, n: usize) -> []T { |
| 78 | return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n); | ||
| 79 | } | ||
| 80 | |||
| 81 | fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29, | ||
| 82 | old_mem: []align(alignment) T, n: usize) -> []align(alignment) T | ||
| 83 | { | ||
| 55 | if (n == 0) { | 84 | if (n == 0) { |
| 56 | self.free(old_mem); | 85 | self.free(old_mem); |
| 57 | return old_mem[0..0]; | 86 | return old_mem[0..0]; |
| ... | @@ -59,15 +88,12 @@ pub const Allocator = struct { | ... | @@ -59,15 +88,12 @@ pub const Allocator = struct { |
| 59 | 88 | ||
| 60 | assert(n <= old_mem.len); | 89 | assert(n <= old_mem.len); |
| 61 | 90 | ||
| 62 | // Assert that old_mem.ptr is properly aligned. | ||
| 63 | const aligned_old_mem = @alignCast(@alignOf(T), old_mem); | ||
| 64 | |||
| 65 | // Here we skip the overflow checking on the multiplication because | 91 | // Here we skip the overflow checking on the multiplication because |
| 66 | // n <= old_mem.len and the multiplication didn't overflow for that operation. | 92 | // n <= old_mem.len and the multiplication didn't overflow for that operation. |
| 67 | const byte_count = @sizeOf(T) * n; | 93 | const byte_count = @sizeOf(T) * n; |
| 68 | 94 | ||
| 69 | const byte_slice = %%self.reallocFn(self, ([]u8)(aligned_old_mem), byte_count, @alignOf(T)); | 95 | const byte_slice = %%self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment); |
| 70 | return ([]T)(@alignCast(@alignOf(T), byte_slice)); | 96 | return ([]align(alignment) T)(@alignCast(alignment, byte_slice)); |
| 71 | } | 97 | } |
| 72 | 98 | ||
| 73 | fn free(self: &Allocator, memory: var) { | 99 | fn free(self: &Allocator, memory: var) { |
| ... | @@ -79,6 +105,51 @@ pub const Allocator = struct { | ... | @@ -79,6 +105,51 @@ pub const Allocator = struct { |
| 79 | } | 105 | } |
| 80 | }; | 106 | }; |
| 81 | 107 | ||
| 108 | pub const FixedBufferAllocator = struct { | ||
| 109 | allocator: Allocator, | ||
| 110 | end_index: usize, | ||
| 111 | buffer: []u8, | ||
| 112 | |||
| 113 | pub fn init(buffer: []u8) -> FixedBufferAllocator { | ||
| 114 | return FixedBufferAllocator { | ||
| 115 | .allocator = Allocator { | ||
| 116 | .allocFn = alloc, | ||
| 117 | .reallocFn = realloc, | ||
| 118 | .freeFn = free, | ||
| 119 | }, | ||
| 120 | .buffer = buffer, | ||
| 121 | .end_index = 0, | ||
| 122 | }; | ||
| 123 | } | ||
| 124 | |||
| 125 | fn alloc(allocator: &Allocator, n: usize, alignment: u29) -> %[]u8 { | ||
| 126 | const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator); | ||
| 127 | const addr = @ptrToInt(&self.buffer[self.end_index]); | ||
| 128 | const rem = @rem(addr, alignment); | ||
| 129 | const march_forward_bytes = if (rem == 0) 0 else (alignment - rem); | ||
| 130 | const adjusted_index = self.end_index + march_forward_bytes; | ||
| 131 | const new_end_index = adjusted_index + n; | ||
| 132 | if (new_end_index > self.buffer.len) { | ||
| 133 | return error.OutOfMemory; | ||
| 134 | } | ||
| 135 | const result = self.buffer[adjusted_index .. new_end_index]; | ||
| 136 | self.end_index = new_end_index; | ||
| 137 | return result; | ||
| 138 | } | ||
| 139 | |||
| 140 | fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 { | ||
| 141 | if (new_size <= old_mem.len) { | ||
| 142 | return old_mem[0..new_size]; | ||
| 143 | } else { | ||
| 144 | const result = %return alloc(allocator, new_size, alignment); | ||
| 145 | copy(u8, result, old_mem); | ||
| 146 | return result; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | fn free(allocator: &Allocator, bytes: []u8) { } | ||
| 151 | }; | ||
| 152 | |||
| 82 | 153 | ||
| 83 | /// Copy all of source into dest at position 0. | 154 | /// Copy all of source into dest at position 0. |
| 84 | /// dest.len must be >= source.len. | 155 | /// dest.len must be >= source.len. |
| ... | @@ -95,17 +166,24 @@ pub fn set(comptime T: type, dest: []T, value: T) { | ... | @@ -95,17 +166,24 @@ pub fn set(comptime T: type, dest: []T, value: T) { |
| 95 | for (dest) |*d| *d = value; | 166 | for (dest) |*d| *d = value; |
| 96 | } | 167 | } |
| 97 | 168 | ||
| 98 | /// Return < 0, == 0, or > 0 if memory a is less than, equal to, or greater than, | 169 | /// Returns true if lhs < rhs, false otherwise |
| 99 | /// memory b, respectively. | 170 | pub fn lessThan(comptime T: type, lhs: []const T, rhs: []const T) -> bool { |
| 100 | pub fn cmp(comptime T: type, a: []const T, b: []const T) -> Cmp { | 171 | const n = math.min(lhs.len, rhs.len); |
| 101 | const n = math.min(a.len, b.len); | ||
| 102 | var i: usize = 0; | 172 | var i: usize = 0; |
| 103 | while (i < n) : (i += 1) { | 173 | while (i < n) : (i += 1) { |
| 104 | if (a[i] == b[i]) continue; | 174 | if (lhs[i] == rhs[i]) continue; |
| 105 | return if (a[i] > b[i]) Cmp.Greater else if (a[i] < b[i]) Cmp.Less else Cmp.Equal; | 175 | return lhs[i] < rhs[i]; |
| 106 | } | 176 | } |
| 107 | 177 | ||
| 108 | return if (a.len > b.len) Cmp.Greater else if (a.len < b.len) Cmp.Less else Cmp.Equal; | 178 | return lhs.len < rhs.len; |
| 179 | } | ||
| 180 | |||
| 181 | test "mem.lessThan" { | ||
| 182 | assert(lessThan(u8, "abcd", "bee")); | ||
| 183 | assert(!lessThan(u8, "abc", "abc")); | ||
| 184 | assert(lessThan(u8, "abc", "abc0")); | ||
| 185 | assert(!lessThan(u8, "", "")); | ||
| 186 | assert(lessThan(u8, "", "a")); | ||
| 109 | } | 187 | } |
| 110 | 188 | ||
| 111 | /// Compares two slices and returns whether they are equal. | 189 | /// Compares two slices and returns whether they are equal. |
| ... | @@ -276,11 +354,11 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) -> bool { | ... | @@ -276,11 +354,11 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) -> bool { |
| 276 | /// split(" abc def ghi ", " ") | 354 | /// split(" abc def ghi ", " ") |
| 277 | /// Will return slices for "abc", "def", "ghi", null, in that order. | 355 | /// Will return slices for "abc", "def", "ghi", null, in that order. |
| 278 | pub fn split(buffer: []const u8, split_bytes: []const u8) -> SplitIterator { | 356 | pub fn split(buffer: []const u8, split_bytes: []const u8) -> SplitIterator { |
| 279 | SplitIterator { | 357 | return SplitIterator { |
| 280 | .index = 0, | 358 | .index = 0, |
| 281 | .buffer = buffer, | 359 | .buffer = buffer, |
| 282 | .split_bytes = split_bytes, | 360 | .split_bytes = split_bytes, |
| 283 | } | 361 | }; |
| 284 | } | 362 | } |
| 285 | 363 | ||
| 286 | test "mem.split" { | 364 | test "mem.split" { |
| ... | @@ -433,9 +511,8 @@ fn testWriteIntImpl() { | ... | @@ -433,9 +511,8 @@ fn testWriteIntImpl() { |
| 433 | 511 | ||
| 434 | pub fn min(comptime T: type, slice: []const T) -> T { | 512 | pub fn min(comptime T: type, slice: []const T) -> T { |
| 435 | var best = slice[0]; | 513 | var best = slice[0]; |
| 436 | var i: usize = 1; | 514 | for (slice[1..]) |item| { |
| 437 | while (i < slice.len) : (i += 1) { | 515 | best = math.min(best, item); |
| 438 | best = math.min(best, slice[i]); | ||
| 439 | } | 516 | } |
| 440 | return best; | 517 | return best; |
| 441 | } | 518 | } |
| ... | @@ -446,9 +523,8 @@ test "mem.min" { | ... | @@ -446,9 +523,8 @@ test "mem.min" { |
| 446 | 523 | ||
| 447 | pub fn max(comptime T: type, slice: []const T) -> T { | 524 | pub fn max(comptime T: type, slice: []const T) -> T { |
| 448 | var best = slice[0]; | 525 | var best = slice[0]; |
| 449 | var i: usize = 1; | 526 | for (slice[1..]) |item| { |
| 450 | while (i < slice.len) : (i += 1) { | 527 | best = math.max(best, item); |
| 451 | best = math.max(best, slice[i]); | ||
| 452 | } | 528 | } |
| 453 | return best; | 529 | return best; |
| 454 | } | 530 | } |
| ... | @@ -456,3 +532,40 @@ pub fn max(comptime T: type, slice: []const T) -> T { | ... | @@ -456,3 +532,40 @@ pub fn max(comptime T: type, slice: []const T) -> T { |
| 456 | test "mem.max" { | 532 | test "mem.max" { |
| 457 | assert(max(u8, "abcdefg") == 'g'); | 533 | assert(max(u8, "abcdefg") == 'g'); |
| 458 | } | 534 | } |
| 535 | |||
| 536 | pub fn swap(comptime T: type, a: &T, b: &T) { | ||
| 537 | const tmp = *a; | ||
| 538 | *a = *b; | ||
| 539 | *b = tmp; | ||
| 540 | } | ||
| 541 | |||
| 542 | /// In-place order reversal of a slice | ||
| 543 | pub fn reverse(comptime T: type, items: []T) { | ||
| 544 | var i: usize = 0; | ||
| 545 | const end = items.len / 2; | ||
| 546 | while (i < end) : (i += 1) { | ||
| 547 | swap(T, &items[i], &items[items.len - i - 1]); | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | test "std.mem.reverse" { | ||
| 552 | var arr = []i32{ 5, 3, 1, 2, 4 }; | ||
| 553 | reverse(i32, arr[0..]); | ||
| 554 | |||
| 555 | assert(eql(i32, arr, []i32{ 4, 2, 1, 3, 5 })); | ||
| 556 | } | ||
| 557 | |||
| 558 | /// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1) | ||
| 559 | /// Assumes 0 <= amount <= items.len | ||
| 560 | pub fn rotate(comptime T: type, items: []T, amount: usize) { | ||
| 561 | reverse(T, items[0..amount]); | ||
| 562 | reverse(T, items[amount..]); | ||
| 563 | reverse(T, items); | ||
| 564 | } | ||
| 565 | |||
| 566 | test "std.mem.rotate" { | ||
| 567 | var arr = []i32{ 5, 3, 1, 2, 4 }; | ||
| 568 | rotate(i32, arr[0..], 2); | ||
| 569 | |||
| 570 | assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 })); | ||
| 571 | } |
std/net.zig+11-11| ... | @@ -72,7 +72,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address { | ... | @@ -72,7 +72,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address { |
| 72 | //		if (family != AF_INET) | 72 | //		if (family != AF_INET) |
| 73 | //			buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } }; | 73 | //			buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } }; |
| 74 | // | 74 | // |
| 75 | unreachable // TODO | 75 | unreachable; // TODO |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | // TODO | 78 | // TODO |
| ... | @@ -84,7 +84,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address { | ... | @@ -84,7 +84,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address { |
| 84 | // else => {}, | 84 | // else => {}, |
| 85 | //}; | 85 | //}; |
| 86 | 86 | ||
| 87 | unreachable // TODO | 87 | unreachable; // TODO |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | pub fn connectAddr(addr: &Address, port: u16) -> %Connection { | 90 | pub fn connectAddr(addr: &Address, port: u16) -> %Connection { |
| ... | @@ -96,23 +96,23 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection { | ... | @@ -96,23 +96,23 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection { |
| 96 | } | 96 | } |
| 97 | const socket_fd = i32(socket_ret); | 97 | const socket_fd = i32(socket_ret); |
| 98 | 98 | ||
| 99 | const connect_ret = if (addr.family == linux.AF_INET) { | 99 | const connect_ret = if (addr.family == linux.AF_INET) x: { |
| 100 | var os_addr: linux.sockaddr_in = undefined; | 100 | var os_addr: linux.sockaddr_in = undefined; |
| 101 | os_addr.family = addr.family; | 101 | os_addr.family = addr.family; |
| 102 | os_addr.port = endian.swapIfLe(u16, port); | 102 | os_addr.port = endian.swapIfLe(u16, port); |
| 103 | @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4); | 103 | @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4); |
| 104 | @memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero))); | 104 | @memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero))); |
| 105 | linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in)) | 105 | break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in)); |
| 106 | } else if (addr.family == linux.AF_INET6) { | 106 | } else if (addr.family == linux.AF_INET6) x: { |
| 107 | var os_addr: linux.sockaddr_in6 = undefined; | 107 | var os_addr: linux.sockaddr_in6 = undefined; |
| 108 | os_addr.family = addr.family; | 108 | os_addr.family = addr.family; |
| 109 | os_addr.port = endian.swapIfLe(u16, port); | 109 | os_addr.port = endian.swapIfLe(u16, port); |
| 110 | os_addr.flowinfo = 0; | 110 | os_addr.flowinfo = 0; |
| 111 | os_addr.scope_id = addr.scope_id; | 111 | os_addr.scope_id = addr.scope_id; |
| 112 | @memcpy(&os_addr.addr[0], &addr.addr[0], 16); | 112 | @memcpy(&os_addr.addr[0], &addr.addr[0], 16); |
| 113 | linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6)) | 113 | break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6)); |
| 114 | } else { | 114 | } else { |
| 115 | unreachable | 115 | unreachable; |
| 116 | }; | 116 | }; |
| 117 | const connect_err = linux.getErrno(connect_ret); | 117 | const connect_err = linux.getErrno(connect_ret); |
| 118 | if (connect_err > 0) { | 118 | if (connect_err > 0) { |
| ... | @@ -165,13 +165,13 @@ pub fn parseIpLiteral(buf: []const u8) -> %Address { | ... | @@ -165,13 +165,13 @@ pub fn parseIpLiteral(buf: []const u8) -> %Address { |
| 165 | fn hexDigit(c: u8) -> u8 { | 165 | fn hexDigit(c: u8) -> u8 { |
| 166 | // TODO use switch with range | 166 | // TODO use switch with range |
| 167 | if ('0' <= c and c <= '9') { | 167 | if ('0' <= c and c <= '9') { |
| 168 | c - '0' | 168 | return c - '0'; |
| 169 | } else if ('A' <= c and c <= 'Z') { | 169 | } else if ('A' <= c and c <= 'Z') { |
| 170 | c - 'A' + 10 | 170 | return c - 'A' + 10; |
| 171 | } else if ('a' <= c and c <= 'z') { | 171 | } else if ('a' <= c and c <= 'z') { |
| 172 | c - 'a' + 10 | 172 | return c - 'a' + 10; |
| 173 | } else { | 173 | } else { |
| 174 | @maxValue(u8) | 174 | return @maxValue(u8); |
| 175 | } | 175 | } |
| 176 | } | 176 | } |
| 177 | 177 |
std/os/child_process.zig+82-40| ... | @@ -5,7 +5,6 @@ const os = std.os; | ... | @@ -5,7 +5,6 @@ const os = std.os; |
| 5 | const posix = os.posix; | 5 | const posix = os.posix; |
| 6 | const windows = os.windows; | 6 | const windows = os.windows; |
| 7 | const mem = std.mem; | 7 | const mem = std.mem; |
| 8 | const Allocator = mem.Allocator; | ||
| 9 | const debug = std.debug; | 8 | const debug = std.debug; |
| 10 | const assert = debug.assert; | 9 | const assert = debug.assert; |
| 11 | const BufMap = std.BufMap; | 10 | const BufMap = std.BufMap; |
| ... | @@ -74,7 +73,7 @@ pub const ChildProcess = struct { | ... | @@ -74,7 +73,7 @@ pub const ChildProcess = struct { |
| 74 | 73 | ||
| 75 | /// First argument in argv is the executable. | 74 | /// First argument in argv is the executable. |
| 76 | /// On success must call deinit. | 75 | /// On success must call deinit. |
| 77 | pub fn init(argv: []const []const u8, allocator: &Allocator) -> %&ChildProcess { | 76 | pub fn init(argv: []const []const u8, allocator: &mem.Allocator) -> %&ChildProcess { |
| 78 | const child = %return allocator.create(ChildProcess); | 77 | const child = %return allocator.create(ChildProcess); |
| 79 | %defer allocator.destroy(child); | 78 | %defer allocator.destroy(child); |
| 80 | 79 | ||
| ... | @@ -116,7 +115,7 @@ pub const ChildProcess = struct { | ... | @@ -116,7 +115,7 @@ pub const ChildProcess = struct { |
| 116 | return self.spawnWindows(); | 115 | return self.spawnWindows(); |
| 117 | } else { | 116 | } else { |
| 118 | return self.spawnPosix(); | 117 | return self.spawnPosix(); |
| 119 | }; | 118 | } |
| 120 | } | 119 | } |
| 121 | 120 | ||
| 122 | pub fn spawnAndWait(self: &ChildProcess) -> %Term { | 121 | pub fn spawnAndWait(self: &ChildProcess) -> %Term { |
| ... | @@ -180,6 +179,46 @@ pub const ChildProcess = struct { | ... | @@ -180,6 +179,46 @@ pub const ChildProcess = struct { |
| 180 | } | 179 | } |
| 181 | } | 180 | } |
| 182 | 181 | ||
| 182 | pub const ExecResult = struct { | ||
| 183 | term: os.ChildProcess.Term, | ||
| 184 | stdout: []u8, | ||
| 185 | stderr: []u8, | ||
| 186 | }; | ||
| 187 | |||
| 188 | /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns. | ||
| 189 | /// If it succeeds, the caller owns result.stdout and result.stderr memory. | ||
| 190 | pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, | ||
| 191 | env_map: ?&const BufMap, max_output_size: usize) -> %ExecResult | ||
| 192 | { | ||
| 193 | const child = %%ChildProcess.init(argv, allocator); | ||
| 194 | defer child.deinit(); | ||
| 195 | |||
| 196 | child.stdin_behavior = ChildProcess.StdIo.Ignore; | ||
| 197 | child.stdout_behavior = ChildProcess.StdIo.Pipe; | ||
| 198 | child.stderr_behavior = ChildProcess.StdIo.Pipe; | ||
| 199 | child.cwd = cwd; | ||
| 200 | child.env_map = env_map; | ||
| 201 | |||
| 202 | %return child.spawn(); | ||
| 203 | |||
| 204 | var stdout = Buffer.initNull(allocator); | ||
| 205 | var stderr = Buffer.initNull(allocator); | ||
| 206 | defer Buffer.deinit(&stdout); | ||
| 207 | defer Buffer.deinit(&stderr); | ||
| 208 | |||
| 209 | var stdout_file_in_stream = io.FileInStream.init(&??child.stdout); | ||
| 210 | var stderr_file_in_stream = io.FileInStream.init(&??child.stderr); | ||
| 211 | |||
| 212 | %return stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size); | ||
| 213 | %return stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size); | ||
| 214 | |||
| 215 | return ExecResult { | ||
| 216 | .term = %return child.wait(), | ||
| 217 | .stdout = stdout.toOwnedSlice(), | ||
| 218 | .stderr = stderr.toOwnedSlice(), | ||
| 219 | }; | ||
| 220 | } | ||
| 221 | |||
| 183 | fn waitWindows(self: &ChildProcess) -> %Term { | 222 | fn waitWindows(self: &ChildProcess) -> %Term { |
| 184 | if (self.term) |term| { | 223 | if (self.term) |term| { |
| 185 | self.cleanupStreams(); | 224 | self.cleanupStreams(); |
| ... | @@ -210,12 +249,12 @@ pub const ChildProcess = struct { | ... | @@ -210,12 +249,12 @@ pub const ChildProcess = struct { |
| 210 | fn waitUnwrappedWindows(self: &ChildProcess) -> %void { | 249 | fn waitUnwrappedWindows(self: &ChildProcess) -> %void { |
| 211 | const result = os.windowsWaitSingle(self.handle, windows.INFINITE); | 250 | const result = os.windowsWaitSingle(self.handle, windows.INFINITE); |
| 212 | 251 | ||
| 213 | self.term = (%Term)({ | 252 | self.term = (%Term)(x: { |
| 214 | var exit_code: windows.DWORD = undefined; | 253 | var exit_code: windows.DWORD = undefined; |
| 215 | if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) { | 254 | if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) { |
| 216 | Term { .Unknown = 0 } | 255 | break :x Term { .Unknown = 0 }; |
| 217 | } else { | 256 | } else { |
| 218 | Term { .Exited = @bitCast(i32, exit_code)} | 257 | break :x Term { .Exited = @bitCast(i32, exit_code)}; |
| 219 | } | 258 | } |
| 220 | }); | 259 | }); |
| 221 | 260 | ||
| ... | @@ -261,7 +300,7 @@ pub const ChildProcess = struct { | ... | @@ -261,7 +300,7 @@ pub const ChildProcess = struct { |
| 261 | defer { | 300 | defer { |
| 262 | os.close(self.err_pipe[0]); | 301 | os.close(self.err_pipe[0]); |
| 263 | os.close(self.err_pipe[1]); | 302 | os.close(self.err_pipe[1]); |
| 264 | }; | 303 | } |
| 265 | 304 | ||
| 266 | // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after | 305 | // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after |
| 267 | // waitpid, so this write is guaranteed to be after the child | 306 | // waitpid, so this write is guaranteed to be after the child |
| ... | @@ -280,15 +319,15 @@ pub const ChildProcess = struct { | ... | @@ -280,15 +319,15 @@ pub const ChildProcess = struct { |
| 280 | } | 319 | } |
| 281 | 320 | ||
| 282 | fn statusToTerm(status: i32) -> Term { | 321 | fn statusToTerm(status: i32) -> Term { |
| 283 | return if (posix.WIFEXITED(status)) { | 322 | return if (posix.WIFEXITED(status)) |
| 284 | Term { .Exited = posix.WEXITSTATUS(status) } | 323 | Term { .Exited = posix.WEXITSTATUS(status) } |
| 285 | } else if (posix.WIFSIGNALED(status)) { | 324 | else if (posix.WIFSIGNALED(status)) |
| 286 | Term { .Signal = posix.WTERMSIG(status) } | 325 | Term { .Signal = posix.WTERMSIG(status) } |
| 287 | } else if (posix.WIFSTOPPED(status)) { | 326 | else if (posix.WIFSTOPPED(status)) |
| 288 | Term { .Stopped = posix.WSTOPSIG(status) } | 327 | Term { .Stopped = posix.WSTOPSIG(status) } |
| 289 | } else { | 328 | else |
| 290 | Term { .Unknown = status } | 329 | Term { .Unknown = status } |
| 291 | }; | 330 | ; |
| 292 | } | 331 | } |
| 293 | 332 | ||
| 294 | fn spawnPosix(self: &ChildProcess) -> %void { | 333 | fn spawnPosix(self: &ChildProcess) -> %void { |
| ... | @@ -305,22 +344,22 @@ pub const ChildProcess = struct { | ... | @@ -305,22 +344,22 @@ pub const ChildProcess = struct { |
| 305 | %defer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); }; | 344 | %defer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); }; |
| 306 | 345 | ||
| 307 | const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore); | 346 | const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore); |
| 308 | const dev_null_fd = if (any_ignore) { | 347 | const dev_null_fd = if (any_ignore) |
| 309 | %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null) | 348 | %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null) |
| 310 | } else { | 349 | else |
| 311 | undefined | 350 | undefined |
| 312 | }; | 351 | ; |
| 313 | defer { if (any_ignore) os.close(dev_null_fd); }; | 352 | defer { if (any_ignore) os.close(dev_null_fd); } |
| 314 | 353 | ||
| 315 | var env_map_owned: BufMap = undefined; | 354 | var env_map_owned: BufMap = undefined; |
| 316 | var we_own_env_map: bool = undefined; | 355 | var we_own_env_map: bool = undefined; |
| 317 | const env_map = if (self.env_map) |env_map| { | 356 | const env_map = if (self.env_map) |env_map| x: { |
| 318 | we_own_env_map = false; | 357 | we_own_env_map = false; |
| 319 | env_map | 358 | break :x env_map; |
| 320 | } else { | 359 | } else x: { |
| 321 | we_own_env_map = true; | 360 | we_own_env_map = true; |
| 322 | env_map_owned = %return os.getEnvMap(self.allocator); | 361 | env_map_owned = %return os.getEnvMap(self.allocator); |
| 323 | &env_map_owned | 362 | break :x &env_map_owned; |
| 324 | }; | 363 | }; |
| 325 | defer { if (we_own_env_map) env_map_owned.deinit(); } | 364 | defer { if (we_own_env_map) env_map_owned.deinit(); } |
| 326 | 365 | ||
| ... | @@ -411,13 +450,13 @@ pub const ChildProcess = struct { | ... | @@ -411,13 +450,13 @@ pub const ChildProcess = struct { |
| 411 | self.stdout_behavior == StdIo.Ignore or | 450 | self.stdout_behavior == StdIo.Ignore or |
| 412 | self.stderr_behavior == StdIo.Ignore); | 451 | self.stderr_behavior == StdIo.Ignore); |
| 413 | 452 | ||
| 414 | const nul_handle = if (any_ignore) { | 453 | const nul_handle = if (any_ignore) |
| 415 | %return os.windowsOpen("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, | 454 | %return os.windowsOpen("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, |
| 416 | windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null) | 455 | windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null) |
| 417 | } else { | 456 | else |
| 418 | undefined | 457 | undefined |
| 419 | }; | 458 | ; |
| 420 | defer { if (any_ignore) os.close(nul_handle); }; | 459 | defer { if (any_ignore) os.close(nul_handle); } |
| 421 | if (any_ignore) { | 460 | if (any_ignore) { |
| 422 | %return windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0); | 461 | %return windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0); |
| 423 | } | 462 | } |
| ... | @@ -503,30 +542,32 @@ pub const ChildProcess = struct { | ... | @@ -503,30 +542,32 @@ pub const ChildProcess = struct { |
| 503 | }; | 542 | }; |
| 504 | var piProcInfo: windows.PROCESS_INFORMATION = undefined; | 543 | var piProcInfo: windows.PROCESS_INFORMATION = undefined; |
| 505 | 544 | ||
| 506 | const cwd_slice = if (self.cwd) |cwd| { | 545 | const cwd_slice = if (self.cwd) |cwd| |
| 507 | %return cstr.addNullByte(self.allocator, cwd) | 546 | %return cstr.addNullByte(self.allocator, cwd) |
| 508 | } else { | 547 | else |
| 509 | null | 548 | null |
| 510 | }; | 549 | ; |
| 511 | defer if (cwd_slice) |cwd| self.allocator.free(cwd); | 550 | defer if (cwd_slice) |cwd| self.allocator.free(cwd); |
| 512 | const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null; | 551 | const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null; |
| 513 | 552 | ||
| 514 | const maybe_envp_buf = if (self.env_map) |env_map| { | 553 | const maybe_envp_buf = if (self.env_map) |env_map| |
| 515 | %return os.createWindowsEnvBlock(self.allocator, env_map) | 554 | %return os.createWindowsEnvBlock(self.allocator, env_map) |
| 516 | } else { | 555 | else |
| 517 | null | 556 | null |
| 518 | }; | 557 | ; |
| 519 | defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf); | 558 | defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf); |
| 520 | const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null; | 559 | const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null; |
| 521 | 560 | ||
| 522 | // the cwd set in ChildProcess is in effect when choosing the executable path | 561 | // the cwd set in ChildProcess is in effect when choosing the executable path |
| 523 | // to match posix semantics | 562 | // to match posix semantics |
| 524 | const app_name = if (self.cwd) |cwd| { | 563 | const app_name = x: { |
| 525 | const resolved = %return os.path.resolve(self.allocator, cwd, self.argv[0]); | 564 | if (self.cwd) |cwd| { |
| 526 | defer self.allocator.free(resolved); | 565 | const resolved = %return os.path.resolve(self.allocator, cwd, self.argv[0]); |
| 527 | %return cstr.addNullByte(self.allocator, resolved) | 566 | defer self.allocator.free(resolved); |
| 528 | } else { | 567 | break :x %return cstr.addNullByte(self.allocator, resolved); |
| 529 | %return cstr.addNullByte(self.allocator, self.argv[0]) | 568 | } else { |
| 569 | break :x %return cstr.addNullByte(self.allocator, self.argv[0]); | ||
| 570 | } | ||
| 530 | }; | 571 | }; |
| 531 | defer self.allocator.free(app_name); | 572 | defer self.allocator.free(app_name); |
| 532 | 573 | ||
| ... | @@ -589,6 +630,7 @@ pub const ChildProcess = struct { | ... | @@ -589,6 +630,7 @@ pub const ChildProcess = struct { |
| 589 | StdIo.Ignore => %return os.posixDup2(dev_null_fd, std_fileno), | 630 | StdIo.Ignore => %return os.posixDup2(dev_null_fd, std_fileno), |
| 590 | } | 631 | } |
| 591 | } | 632 | } |
| 633 | |||
| 592 | }; | 634 | }; |
| 593 | 635 | ||
| 594 | fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8, | 636 | fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8, |
| ... | @@ -611,7 +653,7 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ? | ... | @@ -611,7 +653,7 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ? |
| 611 | 653 | ||
| 612 | /// Caller must dealloc. | 654 | /// Caller must dealloc. |
| 613 | /// Guarantees a null byte at result[result.len]. | 655 | /// Guarantees a null byte at result[result.len]. |
| 614 | fn windowsCreateCommandLine(allocator: &Allocator, argv: []const []const u8) -> %[]u8 { | 656 | fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8) -> %[]u8 { |
| 615 | var buf = %return Buffer.initSize(allocator, 0); | 657 | var buf = %return Buffer.initSize(allocator, 0); |
| 616 | defer buf.deinit(); | 658 | defer buf.deinit(); |
| 617 | 659 | ||
| ... | @@ -701,7 +743,7 @@ fn makePipe() -> %[2]i32 { | ... | @@ -701,7 +743,7 @@ fn makePipe() -> %[2]i32 { |
| 701 | return switch (err) { | 743 | return switch (err) { |
| 702 | posix.EMFILE, posix.ENFILE => error.SystemResources, | 744 | posix.EMFILE, posix.ENFILE => error.SystemResources, |
| 703 | else => os.unexpectedErrorPosix(err), | 745 | else => os.unexpectedErrorPosix(err), |
| 704 | } | 746 | }; |
| 705 | } | 747 | } |
| 706 | return fds; | 748 | return fds; |
| 707 | } | 749 | } |
| ... | @@ -760,10 +802,10 @@ fn handleTerm(pid: i32, status: i32) { | ... | @@ -760,10 +802,10 @@ fn handleTerm(pid: i32, status: i32) { |
| 760 | } | 802 | } |
| 761 | } | 803 | } |
| 762 | 804 | ||
| 763 | const sigchld_set = { | 805 | const sigchld_set = x: { |
| 764 | var signal_set = posix.empty_sigset; | 806 | var signal_set = posix.empty_sigset; |
| 765 | posix.sigaddset(&signal_set, posix.SIGCHLD); | 807 | posix.sigaddset(&signal_set, posix.SIGCHLD); |
| 766 | signal_set | 808 | break :x signal_set; |
| 767 | }; | 809 | }; |
| 768 | 810 | ||
| 769 | fn block_SIGCHLD() { | 811 | fn block_SIGCHLD() { |
std/os/darwin.zig+38-42| ... | @@ -97,63 +97,63 @@ pub const SIGINFO = 29; /// information request | ... | @@ -97,63 +97,63 @@ pub const SIGINFO = 29; /// information request |
| 97 | pub const SIGUSR1 = 30; /// user defined signal 1 | 97 | pub const SIGUSR1 = 30; /// user defined signal 1 |
| 98 | pub const SIGUSR2 = 31; /// user defined signal 2 | 98 | pub const SIGUSR2 = 31; /// user defined signal 2 |
| 99 | 99 | ||
| 100 | fn wstatus(x: i32) -> i32 { x & 0o177 } | 100 | fn wstatus(x: i32) -> i32 { return x & 0o177; } |
| 101 | const wstopped = 0o177; | 101 | const wstopped = 0o177; |
| 102 | pub fn WEXITSTATUS(x: i32) -> i32 { x >> 8 } | 102 | pub fn WEXITSTATUS(x: i32) -> i32 { return x >> 8; } |
| 103 | pub fn WTERMSIG(x: i32) -> i32 { wstatus(x) } | 103 | pub fn WTERMSIG(x: i32) -> i32 { return wstatus(x); } |
| 104 | pub fn WSTOPSIG(x: i32) -> i32 { x >> 8 } | 104 | pub fn WSTOPSIG(x: i32) -> i32 { return x >> 8; } |
| 105 | pub fn WIFEXITED(x: i32) -> bool { wstatus(x) == 0 } | 105 | pub fn WIFEXITED(x: i32) -> bool { return wstatus(x) == 0; } |
| 106 | pub fn WIFSTOPPED(x: i32) -> bool { wstatus(x) == wstopped and WSTOPSIG(x) != 0x13 } | 106 | pub fn WIFSTOPPED(x: i32) -> bool { return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; } |
| 107 | pub fn WIFSIGNALED(x: i32) -> bool { wstatus(x) != wstopped and wstatus(x) != 0 } | 107 | pub fn WIFSIGNALED(x: i32) -> bool { return wstatus(x) != wstopped and wstatus(x) != 0; } |
| 108 | 108 | ||
| 109 | /// Get the errno from a syscall return value, or 0 for no error. | 109 | /// Get the errno from a syscall return value, or 0 for no error. |
| 110 | pub fn getErrno(r: usize) -> usize { | 110 | pub fn getErrno(r: usize) -> usize { |
| 111 | const signed_r = @bitCast(isize, r); | 111 | const signed_r = @bitCast(isize, r); |
| 112 | if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0 | 112 | return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | pub fn close(fd: i32) -> usize { | 115 | pub fn close(fd: i32) -> usize { |
| 116 | errnoWrap(c.close(fd)) | 116 | return errnoWrap(c.close(fd)); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | pub fn abort() -> noreturn { | 119 | pub fn abort() -> noreturn { |
| 120 | c.abort() | 120 | c.abort(); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | pub fn exit(code: i32) -> noreturn { | 123 | pub fn exit(code: i32) -> noreturn { |
| 124 | c.exit(code) | 124 | c.exit(code); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | pub fn isatty(fd: i32) -> bool { | 127 | pub fn isatty(fd: i32) -> bool { |
| 128 | c.isatty(fd) != 0 | 128 | return c.isatty(fd) != 0; |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | pub fn fstat(fd: i32, buf: &c.Stat) -> usize { | 131 | pub fn fstat(fd: i32, buf: &c.Stat) -> usize { |
| 132 | errnoWrap(c.@"fstat$INODE64"(fd, buf)) | 132 | return errnoWrap(c.@"fstat$INODE64"(fd, buf)); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | pub fn lseek(fd: i32, offset: isize, whence: c_int) -> usize { | 135 | pub fn lseek(fd: i32, offset: isize, whence: c_int) -> usize { |
| 136 | errnoWrap(c.lseek(fd, offset, whence)) | 136 | return errnoWrap(c.lseek(fd, offset, whence)); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | pub fn open(path: &const u8, flags: u32, mode: usize) -> usize { | 139 | pub fn open(path: &const u8, flags: u32, mode: usize) -> usize { |
| 140 | errnoWrap(c.open(path, @bitCast(c_int, flags), mode)) | 140 | return errnoWrap(c.open(path, @bitCast(c_int, flags), mode)); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | pub fn raise(sig: i32) -> usize { | 143 | pub fn raise(sig: i32) -> usize { |
| 144 | errnoWrap(c.raise(sig)) | 144 | return errnoWrap(c.raise(sig)); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | pub fn read(fd: i32, buf: &u8, nbyte: usize) -> usize { | 147 | pub fn read(fd: i32, buf: &u8, nbyte: usize) -> usize { |
| 148 | errnoWrap(c.read(fd, @ptrCast(&c_void, buf), nbyte)) | 148 | return errnoWrap(c.read(fd, @ptrCast(&c_void, buf), nbyte)); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | pub fn stat(noalias path: &const u8, noalias buf: &stat) -> usize { | 151 | pub fn stat(noalias path: &const u8, noalias buf: &stat) -> usize { |
| 152 | errnoWrap(c.stat(path, buf)) | 152 | return errnoWrap(c.stat(path, buf)); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | pub fn write(fd: i32, buf: &const u8, nbyte: usize) -> usize { | 155 | pub fn write(fd: i32, buf: &const u8, nbyte: usize) -> usize { |
| 156 | errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte)) | 156 | return errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte)); |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, | 159 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, |
| ... | @@ -166,79 +166,79 @@ pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, | ... | @@ -166,79 +166,79 @@ pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | pub fn munmap(address: &u8, length: usize) -> usize { | 168 | pub fn munmap(address: &u8, length: usize) -> usize { |
| 169 | errnoWrap(c.munmap(@ptrCast(&c_void, address), length)) | 169 | return errnoWrap(c.munmap(@ptrCast(&c_void, address), length)); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | pub fn unlink(path: &const u8) -> usize { | 172 | pub fn unlink(path: &const u8) -> usize { |
| 173 | errnoWrap(c.unlink(path)) | 173 | return errnoWrap(c.unlink(path)); |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | pub fn getcwd(buf: &u8, size: usize) -> usize { | 176 | pub fn getcwd(buf: &u8, size: usize) -> usize { |
| 177 | if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0 | 177 | return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | pub fn waitpid(pid: i32, status: &i32, options: u32) -> usize { | 180 | pub fn waitpid(pid: i32, status: &i32, options: u32) -> usize { |
| 181 | comptime assert(i32.bit_count == c_int.bit_count); | 181 | comptime assert(i32.bit_count == c_int.bit_count); |
| 182 | errnoWrap(c.waitpid(pid, @ptrCast(&c_int, status), @bitCast(c_int, options))) | 182 | return errnoWrap(c.waitpid(pid, @ptrCast(&c_int, status), @bitCast(c_int, options))); |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | pub fn fork() -> usize { | 185 | pub fn fork() -> usize { |
| 186 | errnoWrap(c.fork()) | 186 | return errnoWrap(c.fork()); |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | pub fn pipe(fds: &[2]i32) -> usize { | 189 | pub fn pipe(fds: &[2]i32) -> usize { |
| 190 | comptime assert(i32.bit_count == c_int.bit_count); | 190 | comptime assert(i32.bit_count == c_int.bit_count); |
| 191 | errnoWrap(c.pipe(@ptrCast(&c_int, fds))) | 191 | return errnoWrap(c.pipe(@ptrCast(&c_int, fds))); |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | pub fn mkdir(path: &const u8, mode: u32) -> usize { | 194 | pub fn mkdir(path: &const u8, mode: u32) -> usize { |
| 195 | errnoWrap(c.mkdir(path, mode)) | 195 | return errnoWrap(c.mkdir(path, mode)); |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | pub fn symlink(existing: &const u8, new: &const u8) -> usize { | 198 | pub fn symlink(existing: &const u8, new: &const u8) -> usize { |
| 199 | errnoWrap(c.symlink(existing, new)) | 199 | return errnoWrap(c.symlink(existing, new)); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | pub fn rename(old: &const u8, new: &const u8) -> usize { | 202 | pub fn rename(old: &const u8, new: &const u8) -> usize { |
| 203 | errnoWrap(c.rename(old, new)) | 203 | return errnoWrap(c.rename(old, new)); |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | pub fn chdir(path: &const u8) -> usize { | 206 | pub fn chdir(path: &const u8) -> usize { |
| 207 | errnoWrap(c.chdir(path)) | 207 | return errnoWrap(c.chdir(path)); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) | 210 | pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) |
| 211 | -> usize | 211 | -> usize |
| 212 | { | 212 | { |
| 213 | errnoWrap(c.execve(path, argv, envp)) | 213 | return errnoWrap(c.execve(path, argv, envp)); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | pub fn dup2(old: i32, new: i32) -> usize { | 216 | pub fn dup2(old: i32, new: i32) -> usize { |
| 217 | errnoWrap(c.dup2(old, new)) | 217 | return errnoWrap(c.dup2(old, new)); |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize { | 220 | pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize { |
| 221 | errnoWrap(c.readlink(path, buf_ptr, buf_len)) | 221 | return errnoWrap(c.readlink(path, buf_ptr, buf_len)); |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize { | 224 | pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize { |
| 225 | errnoWrap(c.nanosleep(req, rem)) | 225 | return errnoWrap(c.nanosleep(req, rem)); |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) -> usize { | 228 | pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) -> usize { |
| 229 | if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0 | 229 | return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0; |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | pub fn setreuid(ruid: u32, euid: u32) -> usize { | 232 | pub fn setreuid(ruid: u32, euid: u32) -> usize { |
| 233 | errnoWrap(c.setreuid(ruid, euid)) | 233 | return errnoWrap(c.setreuid(ruid, euid)); |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | pub fn setregid(rgid: u32, egid: u32) -> usize { | 236 | pub fn setregid(rgid: u32, egid: u32) -> usize { |
| 237 | errnoWrap(c.setregid(rgid, egid)) | 237 | return errnoWrap(c.setregid(rgid, egid)); |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { | 240 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { |
| 241 | errnoWrap(c.sigprocmask(@bitCast(c_int, flags), set, oldset)) | 241 | return errnoWrap(c.sigprocmask(@bitCast(c_int, flags), set, oldset)); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize { | 244 | pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize { |
| ... | @@ -285,9 +285,5 @@ pub fn sigaddset(set: &sigset_t, signo: u5) { | ... | @@ -285,9 +285,5 @@ pub fn sigaddset(set: &sigset_t, signo: u5) { |
| 285 | /// that the kernel represents it to libc. Errno was a mistake, let's make | 285 | /// that the kernel represents it to libc. Errno was a mistake, let's make |
| 286 | /// it go away forever. | 286 | /// it go away forever. |
| 287 | fn errnoWrap(value: isize) -> usize { | 287 | fn errnoWrap(value: isize) -> usize { |
| 288 | @bitCast(usize, if (value == -1) { | 288 | return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value); |
| 289 | -isize(*c._errno()) | ||
| 290 | } else { | ||
| 291 | value | ||
| 292 | }) | ||
| 293 | } | 289 | } |
std/os/index.zig+163-81| ... | @@ -84,7 +84,7 @@ pub fn getRandomBytes(buf: []u8) -> %void { | ... | @@ -84,7 +84,7 @@ pub fn getRandomBytes(buf: []u8) -> %void { |
| 84 | posix.EFAULT => unreachable, | 84 | posix.EFAULT => unreachable, |
| 85 | posix.EINTR => continue, | 85 | posix.EINTR => continue, |
| 86 | else => unexpectedErrorPosix(err), | 86 | else => unexpectedErrorPosix(err), |
| 87 | } | 87 | }; |
| 88 | } | 88 | } |
| 89 | return; | 89 | return; |
| 90 | }, | 90 | }, |
| ... | @@ -151,18 +151,17 @@ pub coldcc fn exit(status: i32) -> noreturn { | ... | @@ -151,18 +151,17 @@ pub coldcc fn exit(status: i32) -> noreturn { |
| 151 | } | 151 | } |
| 152 | switch (builtin.os) { | 152 | switch (builtin.os) { |
| 153 | Os.linux, Os.darwin, Os.macosx, Os.ios => { | 153 | Os.linux, Os.darwin, Os.macosx, Os.ios => { |
| 154 | posix.exit(status) | 154 | posix.exit(status); |
| 155 | }, | 155 | }, |
| 156 | Os.windows => { | 156 | Os.windows => { |
| 157 | // Map a possibly negative status code to a non-negative status for the systems default | 157 | // Map a possibly negative status code to a non-negative status for the systems default |
| 158 | // integer width. | 158 | // integer width. |
| 159 | const p_status = if (@sizeOf(c_uint) < @sizeOf(u32)) { | 159 | const p_status = if (@sizeOf(c_uint) < @sizeOf(u32)) |
| 160 | @truncate(c_uint, @bitCast(u32, status)) | 160 | @truncate(c_uint, @bitCast(u32, status)) |
| 161 | } else { | 161 | else |
| 162 | c_uint(@bitCast(u32, status)) | 162 | c_uint(@bitCast(u32, status)); |
| 163 | }; | ||
| 164 | 163 | ||
| 165 | windows.ExitProcess(p_status) | 164 | windows.ExitProcess(p_status); |
| 166 | }, | 165 | }, |
| 167 | else => @compileError("Unsupported OS"), | 166 | else => @compileError("Unsupported OS"), |
| 168 | } | 167 | } |
| ... | @@ -289,7 +288,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al | ... | @@ -289,7 +288,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al |
| 289 | posix.EPERM => error.AccessDenied, | 288 | posix.EPERM => error.AccessDenied, |
| 290 | posix.EEXIST => error.PathAlreadyExists, | 289 | posix.EEXIST => error.PathAlreadyExists, |
| 291 | else => unexpectedErrorPosix(err), | 290 | else => unexpectedErrorPosix(err), |
| 292 | } | 291 | }; |
| 293 | } | 292 | } |
| 294 | return i32(result); | 293 | return i32(result); |
| 295 | } | 294 | } |
| ... | @@ -680,7 +679,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) -> %void | ... | @@ -680,7 +679,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) -> %void |
| 680 | windows.ERROR.ACCESS_DENIED => error.AccessDenied, | 679 | windows.ERROR.ACCESS_DENIED => error.AccessDenied, |
| 681 | windows.ERROR.FILENAME_EXCED_RANGE, windows.ERROR.INVALID_PARAMETER => error.NameTooLong, | 680 | windows.ERROR.FILENAME_EXCED_RANGE, windows.ERROR.INVALID_PARAMETER => error.NameTooLong, |
| 682 | else => unexpectedErrorWindows(err), | 681 | else => unexpectedErrorWindows(err), |
| 683 | } | 682 | }; |
| 684 | } | 683 | } |
| 685 | } | 684 | } |
| 686 | 685 | ||
| ... | @@ -902,40 +901,41 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) -> %void { | ... | @@ -902,40 +901,41 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) -> %void { |
| 902 | /// this function recursively removes its entries and then tries again. | 901 | /// this function recursively removes its entries and then tries again. |
| 903 | // TODO non-recursive implementation | 902 | // TODO non-recursive implementation |
| 904 | pub fn deleteTree(allocator: &Allocator, full_path: []const u8) -> %void { | 903 | pub fn deleteTree(allocator: &Allocator, full_path: []const u8) -> %void { |
| 905 | start_over: | 904 | start_over: while (true) { |
| 906 | // First, try deleting the item as a file. This way we don't follow sym links. | 905 | // First, try deleting the item as a file. This way we don't follow sym links. |
| 907 | if (deleteFile(allocator, full_path)) { | 906 | if (deleteFile(allocator, full_path)) { |
| 908 | return; | ||
| 909 | } else |err| { | ||
| 910 | if (err == error.FileNotFound) | ||
| 911 | return; | 907 | return; |
| 912 | if (err != error.IsDir) | 908 | } else |err| { |
| 913 | return err; | ||
| 914 | } | ||
| 915 | { | ||
| 916 | var dir = Dir.open(allocator, full_path) %% |err| { | ||
| 917 | if (err == error.FileNotFound) | 909 | if (err == error.FileNotFound) |
| 918 | return; | 910 | return; |
| 919 | if (err == error.NotDir) | 911 | if (err != error.IsDir) |
| 920 | goto start_over; | 912 | return err; |
| 921 | return err; | 913 | } |
| 922 | }; | 914 | { |
| 923 | defer dir.close(); | 915 | var dir = Dir.open(allocator, full_path) %% |err| { |
| 916 | if (err == error.FileNotFound) | ||
| 917 | return; | ||
| 918 | if (err == error.NotDir) | ||
| 919 | continue :start_over; | ||
| 920 | return err; | ||
| 921 | }; | ||
| 922 | defer dir.close(); | ||
| 924 | 923 | ||
| 925 | var full_entry_buf = ArrayList(u8).init(allocator); | 924 | var full_entry_buf = ArrayList(u8).init(allocator); |
| 926 | defer full_entry_buf.deinit(); | 925 | defer full_entry_buf.deinit(); |
| 927 | 926 | ||
| 928 | while (%return dir.next()) |entry| { | 927 | while (%return dir.next()) |entry| { |
| 929 | %return full_entry_buf.resize(full_path.len + entry.name.len + 1); | 928 | %return full_entry_buf.resize(full_path.len + entry.name.len + 1); |
| 930 | const full_entry_path = full_entry_buf.toSlice(); | 929 | const full_entry_path = full_entry_buf.toSlice(); |
| 931 | mem.copy(u8, full_entry_path, full_path); | 930 | mem.copy(u8, full_entry_path, full_path); |
| 932 | full_entry_path[full_path.len] = '/'; | 931 | full_entry_path[full_path.len] = '/'; |
| 933 | mem.copy(u8, full_entry_path[full_path.len + 1..], entry.name); | 932 | mem.copy(u8, full_entry_path[full_path.len + 1..], entry.name); |
| 934 | 933 | ||
| 935 | %return deleteTree(allocator, full_entry_path); | 934 | %return deleteTree(allocator, full_entry_path); |
| 935 | } | ||
| 936 | } | 936 | } |
| 937 | return deleteDir(allocator, full_path); | ||
| 937 | } | 938 | } |
| 938 | return deleteDir(allocator, full_path); | ||
| 939 | } | 939 | } |
| 940 | 940 | ||
| 941 | pub const Dir = struct { | 941 | pub const Dir = struct { |
| ... | @@ -988,58 +988,59 @@ pub const Dir = struct { | ... | @@ -988,58 +988,59 @@ pub const Dir = struct { |
| 988 | /// Memory such as file names referenced in this returned entry becomes invalid | 988 | /// Memory such as file names referenced in this returned entry becomes invalid |
| 989 | /// with subsequent calls to next, as well as when this ::Dir is deinitialized. | 989 | /// with subsequent calls to next, as well as when this ::Dir is deinitialized. |
| 990 | pub fn next(self: &Dir) -> %?Entry { | 990 | pub fn next(self: &Dir) -> %?Entry { |
| 991 | start_over: | 991 | start_over: while (true) { |
| 992 | if (self.index >= self.end_index) { | 992 | if (self.index >= self.end_index) { |
| 993 | if (self.buf.len == 0) { | 993 | if (self.buf.len == 0) { |
| 994 | self.buf = %return self.allocator.alloc(u8, page_size); | 994 | self.buf = %return self.allocator.alloc(u8, page_size); |
| 995 | } | 995 | } |
| 996 | 996 | ||
| 997 | while (true) { | 997 | while (true) { |
| 998 | const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len); | 998 | const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len); |
| 999 | const err = linux.getErrno(result); | 999 | const err = linux.getErrno(result); |
| 1000 | if (err > 0) { | 1000 | if (err > 0) { |
| 1001 | switch (err) { | 1001 | switch (err) { |
| 1002 | posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, | 1002 | posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, |
| 1003 | posix.EINVAL => { | 1003 | posix.EINVAL => { |
| 1004 | self.buf = %return self.allocator.realloc(u8, self.buf, self.buf.len * 2); | 1004 | self.buf = %return self.allocator.realloc(u8, self.buf, self.buf.len * 2); |
| 1005 | continue; | 1005 | continue; |
| 1006 | }, | 1006 | }, |
| 1007 | else => return unexpectedErrorPosix(err), | 1007 | else => return unexpectedErrorPosix(err), |
| 1008 | }; | 1008 | } |
| 1009 | } | ||
| 1010 | if (result == 0) | ||
| 1011 | return null; | ||
| 1012 | self.index = 0; | ||
| 1013 | self.end_index = result; | ||
| 1014 | break; | ||
| 1009 | } | 1015 | } |
| 1010 | if (result == 0) | ||
| 1011 | return null; | ||
| 1012 | self.index = 0; | ||
| 1013 | self.end_index = result; | ||
| 1014 | break; | ||
| 1015 | } | 1016 | } |
| 1016 | } | 1017 | const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]); |
| 1017 | const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]); | 1018 | const next_index = self.index + linux_entry.d_reclen; |
| 1018 | const next_index = self.index + linux_entry.d_reclen; | 1019 | self.index = next_index; |
| 1019 | self.index = next_index; | ||
| 1020 | 1020 | ||
| 1021 | const name = cstr.toSlice(&linux_entry.d_name); | 1021 | const name = cstr.toSlice(&linux_entry.d_name); |
| 1022 | 1022 | ||
| 1023 | // skip . and .. entries | 1023 | // skip . and .. entries |
| 1024 | if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) { | 1024 | if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) { |
| 1025 | goto start_over; | 1025 | continue :start_over; |
| 1026 | } | 1026 | } |
| 1027 | 1027 | ||
| 1028 | const type_char = self.buf[next_index - 1]; | 1028 | const type_char = self.buf[next_index - 1]; |
| 1029 | const entry_kind = switch (type_char) { | 1029 | const entry_kind = switch (type_char) { |
| 1030 | posix.DT_BLK => Entry.Kind.BlockDevice, | 1030 | posix.DT_BLK => Entry.Kind.BlockDevice, |
| 1031 | posix.DT_CHR => Entry.Kind.CharacterDevice, | 1031 | posix.DT_CHR => Entry.Kind.CharacterDevice, |
| 1032 | posix.DT_DIR => Entry.Kind.Directory, | 1032 | posix.DT_DIR => Entry.Kind.Directory, |
| 1033 | posix.DT_FIFO => Entry.Kind.NamedPipe, | 1033 | posix.DT_FIFO => Entry.Kind.NamedPipe, |
| 1034 | posix.DT_LNK => Entry.Kind.SymLink, | 1034 | posix.DT_LNK => Entry.Kind.SymLink, |
| 1035 | posix.DT_REG => Entry.Kind.File, | 1035 | posix.DT_REG => Entry.Kind.File, |
| 1036 | posix.DT_SOCK => Entry.Kind.UnixDomainSocket, | 1036 | posix.DT_SOCK => Entry.Kind.UnixDomainSocket, |
| 1037 | else => Entry.Kind.Unknown, | 1037 | else => Entry.Kind.Unknown, |
| 1038 | }; | 1038 | }; |
| 1039 | return Entry { | 1039 | return Entry { |
| 1040 | .name = name, | 1040 | .name = name, |
| 1041 | .kind = entry_kind, | 1041 | .kind = entry_kind, |
| 1042 | }; | 1042 | }; |
| 1043 | } | ||
| 1043 | } | 1044 | } |
| 1044 | }; | 1045 | }; |
| 1045 | 1046 | ||
| ... | @@ -1422,6 +1423,54 @@ pub fn args() -> ArgIterator { | ... | @@ -1422,6 +1423,54 @@ pub fn args() -> ArgIterator { |
| 1422 | return ArgIterator.init(); | 1423 | return ArgIterator.init(); |
| 1423 | } | 1424 | } |
| 1424 | 1425 | ||
| 1426 | /// Caller must call freeArgs on result. | ||
| 1427 | pub fn argsAlloc(allocator: &mem.Allocator) -> %[]const []u8 { | ||
| 1428 | // TODO refactor to only make 1 allocation. | ||
| 1429 | var it = args(); | ||
| 1430 | var contents = %return Buffer.initSize(allocator, 0); | ||
| 1431 | defer contents.deinit(); | ||
| 1432 | |||
| 1433 | var slice_list = ArrayList(usize).init(allocator); | ||
| 1434 | defer slice_list.deinit(); | ||
| 1435 | |||
| 1436 | while (it.next(allocator)) |arg_or_err| { | ||
| 1437 | const arg = %return arg_or_err; | ||
| 1438 | defer allocator.free(arg); | ||
| 1439 | %return contents.append(arg); | ||
| 1440 | %return slice_list.append(arg.len); | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | const contents_slice = contents.toSliceConst(); | ||
| 1444 | const slice_sizes = slice_list.toSliceConst(); | ||
| 1445 | const slice_list_bytes = %return math.mul(usize, @sizeOf([]u8), slice_sizes.len); | ||
| 1446 | const total_bytes = %return math.add(usize, slice_list_bytes, contents_slice.len); | ||
| 1447 | const buf = %return allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes); | ||
| 1448 | %defer allocator.free(buf); | ||
| 1449 | |||
| 1450 | const result_slice_list = ([][]u8)(buf[0..slice_list_bytes]); | ||
| 1451 | const result_contents = buf[slice_list_bytes..]; | ||
| 1452 | mem.copy(u8, result_contents, contents_slice); | ||
| 1453 | |||
| 1454 | var contents_index: usize = 0; | ||
| 1455 | for (slice_sizes) |len, i| { | ||
| 1456 | const new_index = contents_index + len; | ||
| 1457 | result_slice_list[i] = result_contents[contents_index..new_index]; | ||
| 1458 | contents_index = new_index; | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | return result_slice_list; | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | pub fn argsFree(allocator: &mem.Allocator, args_alloc: []const []u8) { | ||
| 1465 | var total_bytes: usize = 0; | ||
| 1466 | for (args_alloc) |arg| { | ||
| 1467 | total_bytes += @sizeOf([]u8) + arg.len; | ||
| 1468 | } | ||
| 1469 | const unaligned_allocated_buf = @ptrCast(&u8, args_alloc.ptr)[0..total_bytes]; | ||
| 1470 | const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf); | ||
| 1471 | return allocator.free(aligned_allocated_buf); | ||
| 1472 | } | ||
| 1473 | |||
| 1425 | test "windows arg parsing" { | 1474 | test "windows arg parsing" { |
| 1426 | testWindowsCmdLine(c"a b\tc d", [][]const u8{"a", "b", "c", "d"}); | 1475 | testWindowsCmdLine(c"a b\tc d", [][]const u8{"a", "b", "c", "d"}); |
| 1427 | testWindowsCmdLine(c"\"abc\" d e", [][]const u8{"abc", "d", "e"}); | 1476 | testWindowsCmdLine(c"\"abc\" d e", [][]const u8{"abc", "d", "e"}); |
| ... | @@ -1494,6 +1543,39 @@ pub fn openSelfExe() -> %io.File { | ... | @@ -1494,6 +1543,39 @@ pub fn openSelfExe() -> %io.File { |
| 1494 | } | 1543 | } |
| 1495 | } | 1544 | } |
| 1496 | 1545 | ||
| 1546 | /// Get the directory path that contains the current executable. | ||
| 1547 | /// Caller owns returned memory. | ||
| 1548 | pub fn selfExeDirPath(allocator: &mem.Allocator) -> %[]u8 { | ||
| 1549 | switch (builtin.os) { | ||
| 1550 | Os.linux => { | ||
| 1551 | // If the currently executing binary has been deleted, | ||
| 1552 | // the file path looks something like `/a/b/c/exe (deleted)` | ||
| 1553 | // This path cannot be opened, but it's valid for determining the directory | ||
| 1554 | // the executable was in when it was run. | ||
| 1555 | const full_exe_path = %return readLink(allocator, "/proc/self/exe"); | ||
| 1556 | %defer allocator.free(full_exe_path); | ||
| 1557 | const dir = path.dirname(full_exe_path); | ||
| 1558 | return allocator.shrink(u8, full_exe_path, dir.len); | ||
| 1559 | }, | ||
| 1560 | Os.windows => { | ||
| 1561 | @panic("TODO windows std.os.selfExeDirPath"); | ||
| 1562 | //buf_resize(out_path, 256); | ||
| 1563 | //for (;;) { | ||
| 1564 | // DWORD copied_amt = GetModuleFileName(nullptr, buf_ptr(out_path), buf_len(out_path)); | ||
| 1565 | // if (copied_amt <= 0) { | ||
| 1566 | // return ErrorFileNotFound; | ||
| 1567 | // } | ||
| 1568 | // if (copied_amt < buf_len(out_path)) { | ||
| 1569 | // buf_resize(out_path, copied_amt); | ||
| 1570 | // return 0; | ||
| 1571 | // } | ||
| 1572 | // buf_resize(out_path, buf_len(out_path) * 2); | ||
| 1573 | //} | ||
| 1574 | }, | ||
| 1575 | else => @compileError("unimplemented: std.os.selfExeDirPath for " ++ @tagName(builtin.os)), | ||
| 1576 | } | ||
| 1577 | } | ||
| 1578 | |||
| 1497 | pub fn isTty(handle: FileHandle) -> bool { | 1579 | pub fn isTty(handle: FileHandle) -> bool { |
| 1498 | if (is_windows) { | 1580 | if (is_windows) { |
| 1499 | return windows_util.windowsIsTty(handle); | 1581 | return windows_util.windowsIsTty(handle); |
std/os/linux.zig+68-90| ... | @@ -367,14 +367,14 @@ pub const TFD_CLOEXEC = O_CLOEXEC; | ... | @@ -367,14 +367,14 @@ pub const TFD_CLOEXEC = O_CLOEXEC; |
| 367 | pub const TFD_TIMER_ABSTIME = 1; | 367 | pub const TFD_TIMER_ABSTIME = 1; |
| 368 | pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1); | 368 | pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1); |
| 369 | 369 | ||
| 370 | fn unsigned(s: i32) -> u32 { @bitCast(u32, s) } | 370 | fn unsigned(s: i32) -> u32 { return @bitCast(u32, s); } |
| 371 | fn signed(s: u32) -> i32 { @bitCast(i32, s) } | 371 | fn signed(s: u32) -> i32 { return @bitCast(i32, s); } |
| 372 | pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) } | 372 | pub fn WEXITSTATUS(s: i32) -> i32 { return signed((unsigned(s) & 0xff00) >> 8); } |
| 373 | pub fn WTERMSIG(s: i32) -> i32 { signed(unsigned(s) & 0x7f) } | 373 | pub fn WTERMSIG(s: i32) -> i32 { return signed(unsigned(s) & 0x7f); } |
| 374 | pub fn WSTOPSIG(s: i32) -> i32 { WEXITSTATUS(s) } | 374 | pub fn WSTOPSIG(s: i32) -> i32 { return WEXITSTATUS(s); } |
| 375 | pub fn WIFEXITED(s: i32) -> bool { WTERMSIG(s) == 0 } | 375 | pub fn WIFEXITED(s: i32) -> bool { return WTERMSIG(s) == 0; } |
| 376 | pub fn WIFSTOPPED(s: i32) -> bool { (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00 } | 376 | pub fn WIFSTOPPED(s: i32) -> bool { return (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00; } |
| 377 | pub fn WIFSIGNALED(s: i32) -> bool { (unsigned(s)&0xffff)-%1 < 0xff } | 377 | pub fn WIFSIGNALED(s: i32) -> bool { return (unsigned(s)&0xffff)-%1 < 0xff; } |
| 378 | 378 | ||
| 379 | 379 | ||
| 380 | pub const winsize = extern struct { | 380 | pub const winsize = extern struct { |
| ... | @@ -387,31 +387,31 @@ pub const winsize = extern struct { | ... | @@ -387,31 +387,31 @@ pub const winsize = extern struct { |
| 387 | /// Get the errno from a syscall return value, or 0 for no error. | 387 | /// Get the errno from a syscall return value, or 0 for no error. |
| 388 | pub fn getErrno(r: usize) -> usize { | 388 | pub fn getErrno(r: usize) -> usize { |
| 389 | const signed_r = @bitCast(isize, r); | 389 | const signed_r = @bitCast(isize, r); |
| 390 | if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0 | 390 | return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0; |
| 391 | } | 391 | } |
| 392 | 392 | ||
| 393 | pub fn dup2(old: i32, new: i32) -> usize { | 393 | pub fn dup2(old: i32, new: i32) -> usize { |
| 394 | arch.syscall2(arch.SYS_dup2, usize(old), usize(new)) | 394 | return arch.syscall2(arch.SYS_dup2, usize(old), usize(new)); |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | pub fn chdir(path: &const u8) -> usize { | 397 | pub fn chdir(path: &const u8) -> usize { |
| 398 | arch.syscall1(arch.SYS_chdir, @ptrToInt(path)) | 398 | return arch.syscall1(arch.SYS_chdir, @ptrToInt(path)); |
| 399 | } | 399 | } |
| 400 | 400 | ||
| 401 | pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize { | 401 | pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize { |
| 402 | arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)) | 402 | return arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); |
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | pub fn fork() -> usize { | 405 | pub fn fork() -> usize { |
| 406 | arch.syscall0(arch.SYS_fork) | 406 | return arch.syscall0(arch.SYS_fork); |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | pub fn getcwd(buf: &u8, size: usize) -> usize { | 409 | pub fn getcwd(buf: &u8, size: usize) -> usize { |
| 410 | arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size) | 410 | return arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size); |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize { | 413 | pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize { |
| 414 | arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count) | 414 | return arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count); |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | pub fn isatty(fd: i32) -> bool { | 417 | pub fn isatty(fd: i32) -> bool { |
| ... | @@ -420,123 +420,123 @@ pub fn isatty(fd: i32) -> bool { | ... | @@ -420,123 +420,123 @@ pub fn isatty(fd: i32) -> bool { |
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize { | 422 | pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize { |
| 423 | arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len) | 423 | return arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); |
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | pub fn mkdir(path: &const u8, mode: u32) -> usize { | 426 | pub fn mkdir(path: &const u8, mode: u32) -> usize { |
| 427 | arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode) | 427 | return arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode); |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) | 430 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) |
| 431 | -> usize | 431 | -> usize |
| 432 | { | 432 | { |
| 433 | arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), | 433 | return arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), |
| 434 | @bitCast(usize, offset)) | 434 | @bitCast(usize, offset)); |
| 435 | } | 435 | } |
| 436 | 436 | ||
| 437 | pub fn munmap(address: &u8, length: usize) -> usize { | 437 | pub fn munmap(address: &u8, length: usize) -> usize { |
| 438 | arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length) | 438 | return arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length); |
| 439 | } | 439 | } |
| 440 | 440 | ||
| 441 | pub fn read(fd: i32, buf: &u8, count: usize) -> usize { | 441 | pub fn read(fd: i32, buf: &u8, count: usize) -> usize { |
| 442 | arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count) | 442 | return arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count); |
| 443 | } | 443 | } |
| 444 | 444 | ||
| 445 | pub fn rmdir(path: &const u8) -> usize { | 445 | pub fn rmdir(path: &const u8) -> usize { |
| 446 | arch.syscall1(arch.SYS_rmdir, @ptrToInt(path)) | 446 | return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path)); |
| 447 | } | 447 | } |
| 448 | 448 | ||
| 449 | pub fn symlink(existing: &const u8, new: &const u8) -> usize { | 449 | pub fn symlink(existing: &const u8, new: &const u8) -> usize { |
| 450 | arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new)) | 450 | return arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); |
| 451 | } | 451 | } |
| 452 | 452 | ||
| 453 | pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize { | 453 | pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize { |
| 454 | arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset) | 454 | return arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset); |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | pub fn pipe(fd: &[2]i32) -> usize { | 457 | pub fn pipe(fd: &[2]i32) -> usize { |
| 458 | pipe2(fd, 0) | 458 | return pipe2(fd, 0); |
| 459 | } | 459 | } |
| 460 | 460 | ||
| 461 | pub fn pipe2(fd: &[2]i32, flags: usize) -> usize { | 461 | pub fn pipe2(fd: &[2]i32, flags: usize) -> usize { |
| 462 | arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags) | 462 | return arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags); |
| 463 | } | 463 | } |
| 464 | 464 | ||
| 465 | pub fn write(fd: i32, buf: &const u8, count: usize) -> usize { | 465 | pub fn write(fd: i32, buf: &const u8, count: usize) -> usize { |
| 466 | arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count) | 466 | return arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count); |
| 467 | } | 467 | } |
| 468 | 468 | ||
| 469 | pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize { | 469 | pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize { |
| 470 | arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset) | 470 | return arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset); |
| 471 | } | 471 | } |
| 472 | 472 | ||
| 473 | pub fn rename(old: &const u8, new: &const u8) -> usize { | 473 | pub fn rename(old: &const u8, new: &const u8) -> usize { |
| 474 | arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new)) | 474 | return arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new)); |
| 475 | } | 475 | } |
| 476 | 476 | ||
| 477 | pub fn open(path: &const u8, flags: u32, perm: usize) -> usize { | 477 | pub fn open(path: &const u8, flags: u32, perm: usize) -> usize { |
| 478 | arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm) | 478 | return arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm); |
| 479 | } | 479 | } |
| 480 | 480 | ||
| 481 | pub fn create(path: &const u8, perm: usize) -> usize { | 481 | pub fn create(path: &const u8, perm: usize) -> usize { |
| 482 | arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm) | 482 | return arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm); |
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize { | 485 | pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize { |
| 486 | arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode) | 486 | return arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode); |
| 487 | } | 487 | } |
| 488 | 488 | ||
| 489 | pub fn close(fd: i32) -> usize { | 489 | pub fn close(fd: i32) -> usize { |
| 490 | arch.syscall1(arch.SYS_close, usize(fd)) | 490 | return arch.syscall1(arch.SYS_close, usize(fd)); |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | pub fn lseek(fd: i32, offset: isize, ref_pos: usize) -> usize { | 493 | pub fn lseek(fd: i32, offset: isize, ref_pos: usize) -> usize { |
| 494 | arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos) | 494 | return arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos); |
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | pub fn exit(status: i32) -> noreturn { | 497 | pub fn exit(status: i32) -> noreturn { |
| 498 | _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status))); | 498 | _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status))); |
| 499 | unreachable | 499 | unreachable; |
| 500 | } | 500 | } |
| 501 | 501 | ||
| 502 | pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize { | 502 | pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize { |
| 503 | arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags)) | 503 | return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags)); |
| 504 | } | 504 | } |
| 505 | 505 | ||
| 506 | pub fn kill(pid: i32, sig: i32) -> usize { | 506 | pub fn kill(pid: i32, sig: i32) -> usize { |
| 507 | arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig)) | 507 | return arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig)); |
| 508 | } | 508 | } |
| 509 | 509 | ||
| 510 | pub fn unlink(path: &const u8) -> usize { | 510 | pub fn unlink(path: &const u8) -> usize { |
| 511 | arch.syscall1(arch.SYS_unlink, @ptrToInt(path)) | 511 | return arch.syscall1(arch.SYS_unlink, @ptrToInt(path)); |
| 512 | } | 512 | } |
| 513 | 513 | ||
| 514 | pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize { | 514 | pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize { |
| 515 | arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0) | 515 | return arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); |
| 516 | } | 516 | } |
| 517 | 517 | ||
| 518 | pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize { | 518 | pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize { |
| 519 | arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)) | 519 | return arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | pub fn setuid(uid: u32) -> usize { | 522 | pub fn setuid(uid: u32) -> usize { |
| 523 | arch.syscall1(arch.SYS_setuid, uid) | 523 | return arch.syscall1(arch.SYS_setuid, uid); |
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | pub fn setgid(gid: u32) -> usize { | 526 | pub fn setgid(gid: u32) -> usize { |
| 527 | arch.syscall1(arch.SYS_setgid, gid) | 527 | return arch.syscall1(arch.SYS_setgid, gid); |
| 528 | } | 528 | } |
| 529 | 529 | ||
| 530 | pub fn setreuid(ruid: u32, euid: u32) -> usize { | 530 | pub fn setreuid(ruid: u32, euid: u32) -> usize { |
| 531 | arch.syscall2(arch.SYS_setreuid, ruid, euid) | 531 | return arch.syscall2(arch.SYS_setreuid, ruid, euid); |
| 532 | } | 532 | } |
| 533 | 533 | ||
| 534 | pub fn setregid(rgid: u32, egid: u32) -> usize { | 534 | pub fn setregid(rgid: u32, egid: u32) -> usize { |
| 535 | arch.syscall2(arch.SYS_setregid, rgid, egid) | 535 | return arch.syscall2(arch.SYS_setregid, rgid, egid); |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { | 538 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { |
| 539 | arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8) | 539 | return arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8); |
| 540 | } | 540 | } |
| 541 | 541 | ||
| 542 | pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize { | 542 | pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize { |
| ... | @@ -651,92 +651,70 @@ pub const iovec = extern struct { | ... | @@ -651,92 +651,70 @@ pub const iovec = extern struct { |
| 651 | iov_len: usize, | 651 | iov_len: usize, |
| 652 | }; | 652 | }; |
| 653 | 653 | ||
| 654 | // | ||
| 655 | //const IF_NAMESIZE = 16; | ||
| 656 | // | ||
| 657 | //export struct ifreq { | ||
| 658 | // ifrn_name: [IF_NAMESIZE]u8, | ||
| 659 | // union { | ||
| 660 | // ifru_addr: sockaddr, | ||
| 661 | // ifru_dstaddr: sockaddr, | ||
| 662 | // ifru_broadaddr: sockaddr, | ||
| 663 | // ifru_netmask: sockaddr, | ||
| 664 | // ifru_hwaddr: sockaddr, | ||
| 665 | // ifru_flags: i16, | ||
| 666 | // ifru_ivalue: i32, | ||
| 667 | // ifru_mtu: i32, | ||
| 668 | // ifru_map: ifmap, | ||
| 669 | // ifru_slave: [IF_NAMESIZE]u8, | ||
| 670 | // ifru_newname: [IF_NAMESIZE]u8, | ||
| 671 | // ifru_data: &u8, | ||
| 672 | // } ifr_ifru; | ||
| 673 | //} | ||
| 674 | // | ||
| 675 | |||
| 676 | pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { | 654 | pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { |
| 677 | arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len)) | 655 | return arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len)); |
| 678 | } | 656 | } |
| 679 | 657 | ||
| 680 | pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { | 658 | pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { |
| 681 | arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len)) | 659 | return arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len)); |
| 682 | } | 660 | } |
| 683 | 661 | ||
| 684 | pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize { | 662 | pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize { |
| 685 | arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol)) | 663 | return arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol)); |
| 686 | } | 664 | } |
| 687 | 665 | ||
| 688 | pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) -> usize { | 666 | pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) -> usize { |
| 689 | arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen)) | 667 | return arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen)); |
| 690 | } | 668 | } |
| 691 | 669 | ||
| 692 | pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) -> usize { | 670 | pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) -> usize { |
| 693 | arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen)) | 671 | return arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen)); |
| 694 | } | 672 | } |
| 695 | 673 | ||
| 696 | pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) -> usize { | 674 | pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) -> usize { |
| 697 | arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags) | 675 | return arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags); |
| 698 | } | 676 | } |
| 699 | 677 | ||
| 700 | pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize { | 678 | pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize { |
| 701 | arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len)) | 679 | return arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len)); |
| 702 | } | 680 | } |
| 703 | 681 | ||
| 704 | pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) -> usize { | 682 | pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) -> usize { |
| 705 | arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags) | 683 | return arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags); |
| 706 | } | 684 | } |
| 707 | 685 | ||
| 708 | pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32, | 686 | pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32, |
| 709 | noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize | 687 | noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize |
| 710 | { | 688 | { |
| 711 | arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)) | 689 | return arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); |
| 712 | } | 690 | } |
| 713 | 691 | ||
| 714 | pub fn shutdown(fd: i32, how: i32) -> usize { | 692 | pub fn shutdown(fd: i32, how: i32) -> usize { |
| 715 | arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how)) | 693 | return arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how)); |
| 716 | } | 694 | } |
| 717 | 695 | ||
| 718 | pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize { | 696 | pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize { |
| 719 | arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len)) | 697 | return arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len)); |
| 720 | } | 698 | } |
| 721 | 699 | ||
| 722 | pub fn listen(fd: i32, backlog: i32) -> usize { | 700 | pub fn listen(fd: i32, backlog: i32) -> usize { |
| 723 | arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog)) | 701 | return arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog)); |
| 724 | } | 702 | } |
| 725 | 703 | ||
| 726 | pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) -> usize { | 704 | pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) -> usize { |
| 727 | arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen)) | 705 | return arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen)); |
| 728 | } | 706 | } |
| 729 | 707 | ||
| 730 | pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> usize { | 708 | pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> usize { |
| 731 | arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0])) | 709 | return arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0])); |
| 732 | } | 710 | } |
| 733 | 711 | ||
| 734 | pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { | 712 | pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { |
| 735 | accept4(fd, addr, len, 0) | 713 | return accept4(fd, addr, len, 0); |
| 736 | } | 714 | } |
| 737 | 715 | ||
| 738 | pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) -> usize { | 716 | pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) -> usize { |
| 739 | arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags) | 717 | return arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags); |
| 740 | } | 718 | } |
| 741 | 719 | ||
| 742 | // error NameTooLong; | 720 | // error NameTooLong; |
| ... | @@ -771,7 +749,7 @@ pub const Stat = arch.Stat; | ... | @@ -771,7 +749,7 @@ pub const Stat = arch.Stat; |
| 771 | pub const timespec = arch.timespec; | 749 | pub const timespec = arch.timespec; |
| 772 | 750 | ||
| 773 | pub fn fstat(fd: i32, stat_buf: &Stat) -> usize { | 751 | pub fn fstat(fd: i32, stat_buf: &Stat) -> usize { |
| 774 | arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf)) | 752 | return arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf)); |
| 775 | } | 753 | } |
| 776 | 754 | ||
| 777 | pub const epoll_data = u64; | 755 | pub const epoll_data = u64; |
| ... | @@ -782,19 +760,19 @@ pub const epoll_event = extern struct { | ... | @@ -782,19 +760,19 @@ pub const epoll_event = extern struct { |
| 782 | }; | 760 | }; |
| 783 | 761 | ||
| 784 | pub fn epoll_create() -> usize { | 762 | pub fn epoll_create() -> usize { |
| 785 | arch.syscall1(arch.SYS_epoll_create, usize(1)) | 763 | return arch.syscall1(arch.SYS_epoll_create, usize(1)); |
| 786 | } | 764 | } |
| 787 | 765 | ||
| 788 | pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) -> usize { | 766 | pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) -> usize { |
| 789 | arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev)) | 767 | return arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev)); |
| 790 | } | 768 | } |
| 791 | 769 | ||
| 792 | pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: i32, timeout: i32) -> usize { | 770 | pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: i32, timeout: i32) -> usize { |
| 793 | arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout)) | 771 | return arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout)); |
| 794 | } | 772 | } |
| 795 | 773 | ||
| 796 | pub fn timerfd_create(clockid: i32, flags: u32) -> usize { | 774 | pub fn timerfd_create(clockid: i32, flags: u32) -> usize { |
| 797 | arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags)) | 775 | return arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags)); |
| 798 | } | 776 | } |
| 799 | 777 | ||
| 800 | pub const itimerspec = extern struct { | 778 | pub const itimerspec = extern struct { |
| ... | @@ -803,11 +781,11 @@ pub const itimerspec = extern struct { | ... | @@ -803,11 +781,11 @@ pub const itimerspec = extern struct { |
| 803 | }; | 781 | }; |
| 804 | 782 | ||
| 805 | pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) -> usize { | 783 | pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) -> usize { |
| 806 | arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value)) | 784 | return arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value)); |
| 807 | } | 785 | } |
| 808 | 786 | ||
| 809 | pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) -> usize { | 787 | pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) -> usize { |
| 810 | arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value)) | 788 | return arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value)); |
| 811 | } | 789 | } |
| 812 | 790 | ||
| 813 | test "import linux_test" { | 791 | test "import linux_test" { |
std/os/linux_i386.zig-10| ... | @@ -502,13 +502,3 @@ pub nakedcc fn restore_rt() { | ... | @@ -502,13 +502,3 @@ pub nakedcc fn restore_rt() { |
| 502 | : [number] "{eax}" (usize(SYS_rt_sigreturn)) | 502 | : [number] "{eax}" (usize(SYS_rt_sigreturn)) |
| 503 | : "rcx", "r11") | 503 | : "rcx", "r11") |
| 504 | } | 504 | } |
| 505 | |||
| 506 | export struct msghdr { | ||
| 507 | msg_name: &u8, | ||
| 508 | msg_namelen: socklen_t, | ||
| 509 | msg_iov: &iovec, | ||
| 510 | msg_iovlen: i32, | ||
| 511 | msg_control: &u8, | ||
| 512 | msg_controllen: socklen_t, | ||
| 513 | msg_flags: i32, | ||
| 514 | } |
std/os/linux_x86_64.zig+16-16| ... | @@ -371,52 +371,52 @@ pub const F_GETOWN_EX = 16; | ... | @@ -371,52 +371,52 @@ pub const F_GETOWN_EX = 16; |
| 371 | pub const F_GETOWNER_UIDS = 17; | 371 | pub const F_GETOWNER_UIDS = 17; |
| 372 | 372 | ||
| 373 | pub fn syscall0(number: usize) -> usize { | 373 | pub fn syscall0(number: usize) -> usize { |
| 374 | asm volatile ("syscall" | 374 | return asm volatile ("syscall" |
| 375 | : [ret] "={rax}" (-> usize) | 375 | : [ret] "={rax}" (-> usize) |
| 376 | : [number] "{rax}" (number) | 376 | : [number] "{rax}" (number) |
| 377 | : "rcx", "r11") | 377 | : "rcx", "r11"); |
| 378 | } | 378 | } |
| 379 | 379 | ||
| 380 | pub fn syscall1(number: usize, arg1: usize) -> usize { | 380 | pub fn syscall1(number: usize, arg1: usize) -> usize { |
| 381 | asm volatile ("syscall" | 381 | return asm volatile ("syscall" |
| 382 | : [ret] "={rax}" (-> usize) | 382 | : [ret] "={rax}" (-> usize) |
| 383 | : [number] "{rax}" (number), | 383 | : [number] "{rax}" (number), |
| 384 | [arg1] "{rdi}" (arg1) | 384 | [arg1] "{rdi}" (arg1) |
| 385 | : "rcx", "r11") | 385 | : "rcx", "r11"); |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | pub fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize { | 388 | pub fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize { |
| 389 | asm volatile ("syscall" | 389 | return asm volatile ("syscall" |
| 390 | : [ret] "={rax}" (-> usize) | 390 | : [ret] "={rax}" (-> usize) |
| 391 | : [number] "{rax}" (number), | 391 | : [number] "{rax}" (number), |
| 392 | [arg1] "{rdi}" (arg1), | 392 | [arg1] "{rdi}" (arg1), |
| 393 | [arg2] "{rsi}" (arg2) | 393 | [arg2] "{rsi}" (arg2) |
| 394 | : "rcx", "r11") | 394 | : "rcx", "r11"); |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { | 397 | pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { |
| 398 | asm volatile ("syscall" | 398 | return asm volatile ("syscall" |
| 399 | : [ret] "={rax}" (-> usize) | 399 | : [ret] "={rax}" (-> usize) |
| 400 | : [number] "{rax}" (number), | 400 | : [number] "{rax}" (number), |
| 401 | [arg1] "{rdi}" (arg1), | 401 | [arg1] "{rdi}" (arg1), |
| 402 | [arg2] "{rsi}" (arg2), | 402 | [arg2] "{rsi}" (arg2), |
| 403 | [arg3] "{rdx}" (arg3) | 403 | [arg3] "{rdx}" (arg3) |
| 404 | : "rcx", "r11") | 404 | : "rcx", "r11"); |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize { | 407 | pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize { |
| 408 | asm volatile ("syscall" | 408 | return asm volatile ("syscall" |
| 409 | : [ret] "={rax}" (-> usize) | 409 | : [ret] "={rax}" (-> usize) |
| 410 | : [number] "{rax}" (number), | 410 | : [number] "{rax}" (number), |
| 411 | [arg1] "{rdi}" (arg1), | 411 | [arg1] "{rdi}" (arg1), |
| 412 | [arg2] "{rsi}" (arg2), | 412 | [arg2] "{rsi}" (arg2), |
| 413 | [arg3] "{rdx}" (arg3), | 413 | [arg3] "{rdx}" (arg3), |
| 414 | [arg4] "{r10}" (arg4) | 414 | [arg4] "{r10}" (arg4) |
| 415 | : "rcx", "r11") | 415 | : "rcx", "r11"); |
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize { | 418 | pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize { |
| 419 | asm volatile ("syscall" | 419 | return asm volatile ("syscall" |
| 420 | : [ret] "={rax}" (-> usize) | 420 | : [ret] "={rax}" (-> usize) |
| 421 | : [number] "{rax}" (number), | 421 | : [number] "{rax}" (number), |
| 422 | [arg1] "{rdi}" (arg1), | 422 | [arg1] "{rdi}" (arg1), |
| ... | @@ -424,13 +424,13 @@ pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz | ... | @@ -424,13 +424,13 @@ pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz |
| 424 | [arg3] "{rdx}" (arg3), | 424 | [arg3] "{rdx}" (arg3), |
| 425 | [arg4] "{r10}" (arg4), | 425 | [arg4] "{r10}" (arg4), |
| 426 | [arg5] "{r8}" (arg5) | 426 | [arg5] "{r8}" (arg5) |
| 427 | : "rcx", "r11") | 427 | : "rcx", "r11"); |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, | 430 | pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, |
| 431 | arg5: usize, arg6: usize) -> usize | 431 | arg5: usize, arg6: usize) -> usize |
| 432 | { | 432 | { |
| 433 | asm volatile ("syscall" | 433 | return asm volatile ("syscall" |
| 434 | : [ret] "={rax}" (-> usize) | 434 | : [ret] "={rax}" (-> usize) |
| 435 | : [number] "{rax}" (number), | 435 | : [number] "{rax}" (number), |
| 436 | [arg1] "{rdi}" (arg1), | 436 | [arg1] "{rdi}" (arg1), |
| ... | @@ -439,14 +439,14 @@ pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz | ... | @@ -439,14 +439,14 @@ pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz |
| 439 | [arg4] "{r10}" (arg4), | 439 | [arg4] "{r10}" (arg4), |
| 440 | [arg5] "{r8}" (arg5), | 440 | [arg5] "{r8}" (arg5), |
| 441 | [arg6] "{r9}" (arg6) | 441 | [arg6] "{r9}" (arg6) |
| 442 | : "rcx", "r11") | 442 | : "rcx", "r11"); |
| 443 | } | 443 | } |
| 444 | 444 | ||
| 445 | pub nakedcc fn restore_rt() { | 445 | pub nakedcc fn restore_rt() { |
| 446 | asm volatile ("syscall" | 446 | return asm volatile ("syscall" |
| 447 | : | 447 | : |
| 448 | : [number] "{rax}" (usize(SYS_rt_sigreturn)) | 448 | : [number] "{rax}" (usize(SYS_rt_sigreturn)) |
| 449 | : "rcx", "r11") | 449 | : "rcx", "r11"); |
| 450 | } | 450 | } |
| 451 | 451 | ||
| 452 | 452 |
std/os/path.zig+19-19| ... | @@ -749,21 +749,19 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) | ... | @@ -749,21 +749,19 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) |
| 749 | const resolved_to = %return resolveWindows(allocator, [][]const u8{to}); | 749 | const resolved_to = %return resolveWindows(allocator, [][]const u8{to}); |
| 750 | defer if (clean_up_resolved_to) allocator.free(resolved_to); | 750 | defer if (clean_up_resolved_to) allocator.free(resolved_to); |
| 751 | 751 | ||
| 752 | const result_is_to = if (drive(resolved_to)) |to_drive| { | 752 | const result_is_to = if (drive(resolved_to)) |to_drive| |
| 753 | if (drive(resolved_from)) |from_drive| { | 753 | if (drive(resolved_from)) |from_drive| |
| 754 | asciiUpper(from_drive[0]) != asciiUpper(to_drive[0]) | 754 | asciiUpper(from_drive[0]) != asciiUpper(to_drive[0]) |
| 755 | } else { | 755 | else |
| 756 | true | 756 | true |
| 757 | } | 757 | else if (networkShare(resolved_to)) |to_ns| |
| 758 | } else if (networkShare(resolved_to)) |to_ns| { | 758 | if (networkShare(resolved_from)) |from_ns| |
| 759 | if (networkShare(resolved_from)) |from_ns| { | ||
| 760 | !networkShareServersEql(to_ns, from_ns) | 759 | !networkShareServersEql(to_ns, from_ns) |
| 761 | } else { | 760 | else |
| 762 | true | 761 | true |
| 763 | } | 762 | else |
| 764 | } else { | 763 | unreachable; |
| 765 | unreachable | 764 | |
| 766 | }; | ||
| 767 | if (result_is_to) { | 765 | if (result_is_to) { |
| 768 | clean_up_resolved_to = false; | 766 | clean_up_resolved_to = false; |
| 769 | return resolved_to; | 767 | return resolved_to; |
| ... | @@ -964,14 +962,16 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 { | ... | @@ -964,14 +962,16 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 { |
| 964 | 962 | ||
| 965 | // windows returns \\?\ prepended to the path | 963 | // windows returns \\?\ prepended to the path |
| 966 | // we strip it because nobody wants \\?\ prepended to their path | 964 | // we strip it because nobody wants \\?\ prepended to their path |
| 967 | const final_len = if (result > 4 and mem.startsWith(u8, buf, "\\\\?\\")) { | 965 | const final_len = x: { |
| 968 | var i: usize = 4; | 966 | if (result > 4 and mem.startsWith(u8, buf, "\\\\?\\")) { |
| 969 | while (i < result) : (i += 1) { | 967 | var i: usize = 4; |
| 970 | buf[i - 4] = buf[i]; | 968 | while (i < result) : (i += 1) { |
| 969 | buf[i - 4] = buf[i]; | ||
| 970 | } | ||
| 971 | break :x result - 4; | ||
| 972 | } else { | ||
| 973 | break :x result; | ||
| 971 | } | 974 | } |
| 972 | result - 4 | ||
| 973 | } else { | ||
| 974 | result | ||
| 975 | }; | 975 | }; |
| 976 | 976 | ||
| 977 | return allocator.shrink(u8, buf, final_len); | 977 | return allocator.shrink(u8, buf, final_len); |
| ... | @@ -1012,7 +1012,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 { | ... | @@ -1012,7 +1012,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 { |
| 1012 | defer os.close(fd); | 1012 | defer os.close(fd); |
| 1013 | 1013 | ||
| 1014 | var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined; | 1014 | var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined; |
| 1015 | const proc_path = fmt.bufPrint(buf[0..], "/proc/self/fd/{}", fd); | 1015 | const proc_path = %%fmt.bufPrint(buf[0..], "/proc/self/fd/{}", fd); |
| 1016 | 1016 | ||
| 1017 | return os.readLink(allocator, proc_path); | 1017 | return os.readLink(allocator, proc_path); |
| 1018 | }, | 1018 | }, |
std/os/windows/util.zig+5-5| ... | @@ -16,11 +16,11 @@ pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) -> | ... | @@ -16,11 +16,11 @@ pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) -> |
| 16 | windows.WAIT_ABANDONED => error.WaitAbandoned, | 16 | windows.WAIT_ABANDONED => error.WaitAbandoned, |
| 17 | windows.WAIT_OBJECT_0 => {}, | 17 | windows.WAIT_OBJECT_0 => {}, |
| 18 | windows.WAIT_TIMEOUT => error.WaitTimeOut, | 18 | windows.WAIT_TIMEOUT => error.WaitTimeOut, |
| 19 | windows.WAIT_FAILED => { | 19 | windows.WAIT_FAILED => x: { |
| 20 | const err = windows.GetLastError(); | 20 | const err = windows.GetLastError(); |
| 21 | switch (err) { | 21 | break :x switch (err) { |
| 22 | else => os.unexpectedErrorWindows(err), | 22 | else => os.unexpectedErrorWindows(err), |
| 23 | } | 23 | }; |
| 24 | }, | 24 | }, |
| 25 | else => error.Unexpected, | 25 | else => error.Unexpected, |
| 26 | }; | 26 | }; |
| ... | @@ -122,7 +122,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m | ... | @@ -122,7 +122,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m |
| 122 | /// Caller must free result. | 122 | /// Caller must free result. |
| 123 | pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 { | 123 | pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 { |
| 124 | // count bytes needed | 124 | // count bytes needed |
| 125 | const bytes_needed = { | 125 | const bytes_needed = x: { |
| 126 | var bytes_needed: usize = 1; // 1 for the final null byte | 126 | var bytes_needed: usize = 1; // 1 for the final null byte |
| 127 | var it = env_map.iterator(); | 127 | var it = env_map.iterator(); |
| 128 | while (it.next()) |pair| { | 128 | while (it.next()) |pair| { |
| ... | @@ -130,7 +130,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) | ... | @@ -130,7 +130,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) |
| 130 | // +1 for null byte | 130 | // +1 for null byte |
| 131 | bytes_needed += pair.key.len + pair.value.len + 2; | 131 | bytes_needed += pair.key.len + pair.value.len + 2; |
| 132 | } | 132 | } |
| 133 | bytes_needed | 133 | break :x bytes_needed; |
| 134 | }; | 134 | }; |
| 135 | const result = %return allocator.alloc(u8, bytes_needed); | 135 | const result = %return allocator.alloc(u8, bytes_needed); |
| 136 | %defer allocator.free(result); | 136 | %defer allocator.free(result); |
std/rand.zig+14-14| ... | @@ -28,9 +28,9 @@ pub const Rand = struct { | ... | @@ -28,9 +28,9 @@ pub const Rand = struct { |
| 28 | 28 | ||
| 29 | /// Initialize random state with the given seed. | 29 | /// Initialize random state with the given seed. |
| 30 | pub fn init(seed: usize) -> Rand { | 30 | pub fn init(seed: usize) -> Rand { |
| 31 | Rand { | 31 | return Rand { |
| 32 | .rng = Rng.init(seed), | 32 | .rng = Rng.init(seed), |
| 33 | } | 33 | }; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | /// Get an integer or boolean with random bits. | 36 | /// Get an integer or boolean with random bits. |
| ... | @@ -78,13 +78,13 @@ pub const Rand = struct { | ... | @@ -78,13 +78,13 @@ pub const Rand = struct { |
| 78 | const end_uint = uint(end); | 78 | const end_uint = uint(end); |
| 79 | const total_range = math.absCast(start) + end_uint; | 79 | const total_range = math.absCast(start) + end_uint; |
| 80 | const value = r.range(uint, 0, total_range); | 80 | const value = r.range(uint, 0, total_range); |
| 81 | const result = if (value < end_uint) { | 81 | const result = if (value < end_uint) x: { |
| 82 | T(value) | 82 | break :x T(value); |
| 83 | } else if (value == end_uint) { | 83 | } else if (value == end_uint) x: { |
| 84 | start | 84 | break :x start; |
| 85 | } else { | 85 | } else x: { |
| 86 | // Can't overflow because the range is over signed ints | 86 | // Can't overflow because the range is over signed ints |
| 87 | %%math.negateCast(value - end_uint) | 87 | break :x %%math.negateCast(value - end_uint); |
| 88 | }; | 88 | }; |
| 89 | return result; | 89 | return result; |
| 90 | } else { | 90 | } else { |
| ... | @@ -114,13 +114,13 @@ pub const Rand = struct { | ... | @@ -114,13 +114,13 @@ pub const Rand = struct { |
| 114 | // const rand_bits = r.rng.scalar(int) & mask; | 114 | // const rand_bits = r.rng.scalar(int) & mask; |
| 115 | // return @float_compose(T, false, 0, rand_bits) - 1.0 | 115 | // return @float_compose(T, false, 0, rand_bits) - 1.0 |
| 116 | const int_type = @IntType(false, @sizeOf(T) * 8); | 116 | const int_type = @IntType(false, @sizeOf(T) * 8); |
| 117 | const precision = if (T == f32) { | 117 | const precision = if (T == f32) |
| 118 | 16777216 | 118 | 16777216 |
| 119 | } else if (T == f64) { | 119 | else if (T == f64) |
| 120 | 9007199254740992 | 120 | 9007199254740992 |
| 121 | } else { | 121 | else |
| 122 | @compileError("unknown floating point type") | 122 | @compileError("unknown floating point type") |
| 123 | }; | 123 | ; |
| 124 | return T(r.range(int_type, 0, precision)) / T(precision); | 124 | return T(r.range(int_type, 0, precision)) / T(precision); |
| 125 | } | 125 | } |
| 126 | }; | 126 | }; |
| ... | @@ -133,7 +133,7 @@ fn MersenneTwister( | ... | @@ -133,7 +133,7 @@ fn MersenneTwister( |
| 133 | comptime t: math.Log2Int(int), comptime c: int, | 133 | comptime t: math.Log2Int(int), comptime c: int, |
| 134 | comptime l: math.Log2Int(int), comptime f: int) -> type | 134 | comptime l: math.Log2Int(int), comptime f: int) -> type |
| 135 | { | 135 | { |
| 136 | struct { | 136 | return struct { |
| 137 | const Self = this; | 137 | const Self = this; |
| 138 | 138 | ||
| 139 | array: [n]int, | 139 | array: [n]int, |
| ... | @@ -189,7 +189,7 @@ fn MersenneTwister( | ... | @@ -189,7 +189,7 @@ fn MersenneTwister( |
| 189 | 189 | ||
| 190 | return x; | 190 | return x; |
| 191 | } | 191 | } |
| 192 | } | 192 | }; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | test "rand float 32" { | 195 | test "rand float 32" { |
std/sort.zig+1022-50| ... | @@ -1,75 +1,966 @@ | ... | @@ -1,75 +1,966 @@ |
| 1 | const assert = @import("debug.zig").assert; | 1 | const std = @import("index.zig"); |
| 2 | const mem = @import("mem.zig"); | 2 | const assert = std.debug.assert; |
| 3 | const math = @import("math/index.zig"); | 3 | const mem = std.mem; |
| 4 | const math = std.math; | ||
| 5 | const builtin = @import("builtin"); | ||
| 4 | 6 | ||
| 5 | pub const Cmp = math.Cmp; | 7 | /// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required). |
| 6 | 8 | pub fn insertionSort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)->bool) { | |
| 7 | /// Stable sort using O(1) space. Currently implemented as insertion sort. | 9 | {var i: usize = 1; while (i < items.len) : (i += 1) { |
| 8 | pub fn sort_stable(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) { | 10 | const x = items[i]; |
| 9 | {var i: usize = 1; while (i < array.len) : (i += 1) { | ||
| 10 | const x = array[i]; | ||
| 11 | var j: usize = i; | 11 | var j: usize = i; |
| 12 | while (j > 0 and cmp(array[j - 1], x) == Cmp.Greater) : (j -= 1) { | 12 | while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) { |
| 13 | array[j] = array[j - 1]; | 13 | items[j] = items[j - 1]; |
| 14 | } | 14 | } |
| 15 | array[j] = x; | 15 | items[j] = x; |
| 16 | }} | 16 | }} |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | /// Unstable sort using O(n) stack space. Currently implemented as quicksort. | 19 | const Range = struct { |
| 20 | pub fn sort(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) { | 20 | start: usize, |
| 21 | if (array.len > 0) { | 21 | end: usize, |
| 22 | quicksort(T, array, 0, array.len - 1, cmp); | 22 | |
| 23 | fn init(start: usize, end: usize) -> Range { | ||
| 24 | return Range { .start = start, .end = end }; | ||
| 25 | } | ||
| 26 | |||
| 27 | fn length(self: &const Range) -> usize { | ||
| 28 | return self.end - self.start; | ||
| 29 | } | ||
| 30 | }; | ||
| 31 | |||
| 32 | |||
| 33 | const Iterator = struct { | ||
| 34 | size: usize, | ||
| 35 | power_of_two: usize, | ||
| 36 | numerator: usize, | ||
| 37 | decimal: usize, | ||
| 38 | denominator: usize, | ||
| 39 | decimal_step: usize, | ||
| 40 | numerator_step: usize, | ||
| 41 | |||
| 42 | fn init(size2: usize, min_level: usize) -> Iterator { | ||
| 43 | const power_of_two = math.floorPowerOfTwo(usize, size2); | ||
| 44 | const denominator = power_of_two / min_level; | ||
| 45 | return Iterator { | ||
| 46 | .numerator = 0, | ||
| 47 | .decimal = 0, | ||
| 48 | .size = size2, | ||
| 49 | .power_of_two = power_of_two, | ||
| 50 | .denominator = denominator, | ||
| 51 | .decimal_step = size2 / denominator, | ||
| 52 | .numerator_step = size2 % denominator, | ||
| 53 | }; | ||
| 54 | } | ||
| 55 | |||
| 56 | fn begin(self: &Iterator) { | ||
| 57 | self.numerator = 0; | ||
| 58 | self.decimal = 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | fn nextRange(self: &Iterator) -> Range { | ||
| 62 | const start = self.decimal; | ||
| 63 | |||
| 64 | self.decimal += self.decimal_step; | ||
| 65 | self.numerator += self.numerator_step; | ||
| 66 | if (self.numerator >= self.denominator) { | ||
| 67 | self.numerator -= self.denominator; | ||
| 68 | self.decimal += 1; | ||
| 69 | } | ||
| 70 | |||
| 71 | return Range {.start = start, .end = self.decimal}; | ||
| 72 | } | ||
| 73 | |||
| 74 | fn finished(self: &Iterator) -> bool { | ||
| 75 | return self.decimal >= self.size; | ||
| 76 | } | ||
| 77 | |||
| 78 | fn nextLevel(self: &Iterator) -> bool { | ||
| 79 | self.decimal_step += self.decimal_step; | ||
| 80 | self.numerator_step += self.numerator_step; | ||
| 81 | if (self.numerator_step >= self.denominator) { | ||
| 82 | self.numerator_step -= self.denominator; | ||
| 83 | self.decimal_step += 1; | ||
| 84 | } | ||
| 85 | |||
| 86 | return (self.decimal_step < self.size); | ||
| 87 | } | ||
| 88 | |||
| 89 | fn length(self: &Iterator) -> usize { | ||
| 90 | return self.decimal_step; | ||
| 91 | } | ||
| 92 | }; | ||
| 93 | |||
| 94 | const Pull = struct { | ||
| 95 | from: usize, | ||
| 96 | to: usize, | ||
| 97 | count: usize, | ||
| 98 | range: Range, | ||
| 99 | }; | ||
| 100 | |||
| 101 | /// Stable in-place sort. O(n) best case, O(n*log(n)) worst case and average case. O(1) memory (no allocator required). | ||
| 102 | /// Currently implemented as block sort. | ||
| 103 | pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)->bool) { | ||
| 104 | // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c | ||
| 105 | var cache: [512]T = undefined; | ||
| 106 | |||
| 107 | if (items.len < 4) { | ||
| 108 | if (items.len == 3) { | ||
| 109 | // hard coded insertion sort | ||
| 110 | if (lessThan(items[1], items[0])) mem.swap(T, &items[0], &items[1]); | ||
| 111 | if (lessThan(items[2], items[1])) { | ||
| 112 | mem.swap(T, &items[1], &items[2]); | ||
| 113 | if (lessThan(items[1], items[0])) mem.swap(T, &items[0], &items[1]); | ||
| 114 | } | ||
| 115 | } else if (items.len == 2) { | ||
| 116 | if (lessThan(items[1], items[0])) mem.swap(T, &items[0], &items[1]); | ||
| 117 | } | ||
| 118 | return; | ||
| 119 | } | ||
| 120 | |||
| 121 | // sort groups of 4-8 items at a time using an unstable sorting network, | ||
| 122 | // but keep track of the original item orders to force it to be stable | ||
| 123 | // http://pages.ripco.net/~jgamble/nw.html | ||
| 124 | var iterator = Iterator.init(items.len, 4); | ||
| 125 | while (!iterator.finished()) { | ||
| 126 | var order = []u8{0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 127 | const range = iterator.nextRange(); | ||
| 128 | |||
| 129 | const sliced_items = items[range.start..]; | ||
| 130 | switch (range.length()) { | ||
| 131 | 8 => { | ||
| 132 | swap(T, sliced_items, lessThan, &order, 0, 1); | ||
| 133 | swap(T, sliced_items, lessThan, &order, 2, 3); | ||
| 134 | swap(T, sliced_items, lessThan, &order, 4, 5); | ||
| 135 | swap(T, sliced_items, lessThan, &order, 6, 7); | ||
| 136 | swap(T, sliced_items, lessThan, &order, 0, 2); | ||
| 137 | swap(T, sliced_items, lessThan, &order, 1, 3); | ||
| 138 | swap(T, sliced_items, lessThan, &order, 4, 6); | ||
| 139 | swap(T, sliced_items, lessThan, &order, 5, 7); | ||
| 140 | swap(T, sliced_items, lessThan, &order, 1, 2); | ||
| 141 | swap(T, sliced_items, lessThan, &order, 5, 6); | ||
| 142 | swap(T, sliced_items, lessThan, &order, 0, 4); | ||
| 143 | swap(T, sliced_items, lessThan, &order, 3, 7); | ||
| 144 | swap(T, sliced_items, lessThan, &order, 1, 5); | ||
| 145 | swap(T, sliced_items, lessThan, &order, 2, 6); | ||
| 146 | swap(T, sliced_items, lessThan, &order, 1, 4); | ||
| 147 | swap(T, sliced_items, lessThan, &order, 3, 6); | ||
| 148 | swap(T, sliced_items, lessThan, &order, 2, 4); | ||
| 149 | swap(T, sliced_items, lessThan, &order, 3, 5); | ||
| 150 | swap(T, sliced_items, lessThan, &order, 3, 4); | ||
| 151 | }, | ||
| 152 | 7 => { | ||
| 153 | swap(T, sliced_items, lessThan, &order, 1, 2); | ||
| 154 | swap(T, sliced_items, lessThan, &order, 3, 4); | ||
| 155 | swap(T, sliced_items, lessThan, &order, 5, 6); | ||
| 156 | swap(T, sliced_items, lessThan, &order, 0, 2); | ||
| 157 | swap(T, sliced_items, lessThan, &order, 3, 5); | ||
| 158 | swap(T, sliced_items, lessThan, &order, 4, 6); | ||
| 159 | swap(T, sliced_items, lessThan, &order, 0, 1); | ||
| 160 | swap(T, sliced_items, lessThan, &order, 4, 5); | ||
| 161 | swap(T, sliced_items, lessThan, &order, 2, 6); | ||
| 162 | swap(T, sliced_items, lessThan, &order, 0, 4); | ||
| 163 | swap(T, sliced_items, lessThan, &order, 1, 5); | ||
| 164 | swap(T, sliced_items, lessThan, &order, 0, 3); | ||
| 165 | swap(T, sliced_items, lessThan, &order, 2, 5); | ||
| 166 | swap(T, sliced_items, lessThan, &order, 1, 3); | ||
| 167 | swap(T, sliced_items, lessThan, &order, 2, 4); | ||
| 168 | swap(T, sliced_items, lessThan, &order, 2, 3); | ||
| 169 | }, | ||
| 170 | 6 => { | ||
| 171 | swap(T, sliced_items, lessThan, &order, 1, 2); | ||
| 172 | swap(T, sliced_items, lessThan, &order, 4, 5); | ||
| 173 | swap(T, sliced_items, lessThan, &order, 0, 2); | ||
| 174 | swap(T, sliced_items, lessThan, &order, 3, 5); | ||
| 175 | swap(T, sliced_items, lessThan, &order, 0, 1); | ||
| 176 | swap(T, sliced_items, lessThan, &order, 3, 4); | ||
| 177 | swap(T, sliced_items, lessThan, &order, 2, 5); | ||
| 178 | swap(T, sliced_items, lessThan, &order, 0, 3); | ||
| 179 | swap(T, sliced_items, lessThan, &order, 1, 4); | ||
| 180 | swap(T, sliced_items, lessThan, &order, 2, 4); | ||
| 181 | swap(T, sliced_items, lessThan, &order, 1, 3); | ||
| 182 | swap(T, sliced_items, lessThan, &order, 2, 3); | ||
| 183 | }, | ||
| 184 | 5 => { | ||
| 185 | swap(T, sliced_items, lessThan, &order, 0, 1); | ||
| 186 | swap(T, sliced_items, lessThan, &order, 3, 4); | ||
| 187 | swap(T, sliced_items, lessThan, &order, 2, 4); | ||
| 188 | swap(T, sliced_items, lessThan, &order, 2, 3); | ||
| 189 | swap(T, sliced_items, lessThan, &order, 1, 4); | ||
| 190 | swap(T, sliced_items, lessThan, &order, 0, 3); | ||
| 191 | swap(T, sliced_items, lessThan, &order, 0, 2); | ||
| 192 | swap(T, sliced_items, lessThan, &order, 1, 3); | ||
| 193 | swap(T, sliced_items, lessThan, &order, 1, 2); | ||
| 194 | }, | ||
| 195 | 4 => { | ||
| 196 | swap(T, sliced_items, lessThan, &order, 0, 1); | ||
| 197 | swap(T, sliced_items, lessThan, &order, 2, 3); | ||
| 198 | swap(T, sliced_items, lessThan, &order, 0, 2); | ||
| 199 | swap(T, sliced_items, lessThan, &order, 1, 3); | ||
| 200 | swap(T, sliced_items, lessThan, &order, 1, 2); | ||
| 201 | }, | ||
| 202 | else => {}, | ||
| 203 | } | ||
| 204 | } | ||
| 205 | if (items.len < 8) return; | ||
| 206 | |||
| 207 | // then merge sort the higher levels, which can be 8-15, 16-31, 32-63, 64-127, etc. | ||
| 208 | while (true) { | ||
| 209 | // if every A and B block will fit into the cache, use a special branch specifically for merging with the cache | ||
| 210 | // (we use < rather than <= since the block size might be one more than iterator.length()) | ||
| 211 | if (iterator.length() < cache.len) { | ||
| 212 | // if four subarrays fit into the cache, it's faster to merge both pairs of subarrays into the cache, | ||
| 213 | // then merge the two merged subarrays from the cache back into the original array | ||
| 214 | if ((iterator.length() + 1) * 4 <= cache.len and iterator.length() * 4 <= items.len) { | ||
| 215 | iterator.begin(); | ||
| 216 | while (!iterator.finished()) { | ||
| 217 | // merge A1 and B1 into the cache | ||
| 218 | var A1 = iterator.nextRange(); | ||
| 219 | var B1 = iterator.nextRange(); | ||
| 220 | var A2 = iterator.nextRange(); | ||
| 221 | var B2 = iterator.nextRange(); | ||
| 222 | |||
| 223 | if (lessThan(items[B1.end - 1], items[A1.start])) { | ||
| 224 | // the two ranges are in reverse order, so copy them in reverse order into the cache | ||
| 225 | mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]); | ||
| 226 | mem.copy(T, cache[0..], items[B1.start..B1.end]); | ||
| 227 | } else if (lessThan(items[B1.start], items[A1.end - 1])) { | ||
| 228 | // these two ranges weren't already in order, so merge them into the cache | ||
| 229 | mergeInto(T, items, A1, B1, lessThan, cache[0..]); | ||
| 230 | } else { | ||
| 231 | // if A1, B1, A2, and B2 are all in order, skip doing anything else | ||
| 232 | if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue; | ||
| 233 | |||
| 234 | // copy A1 and B1 into the cache in the same order | ||
| 235 | mem.copy(T, cache[0..], items[A1.start..A1.end]); | ||
| 236 | mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]); | ||
| 237 | } | ||
| 238 | A1 = Range.init(A1.start, B1.end); | ||
| 239 | |||
| 240 | // merge A2 and B2 into the cache | ||
| 241 | if (lessThan(items[B2.end - 1], items[A2.start])) { | ||
| 242 | // the two ranges are in reverse order, so copy them in reverse order into the cache | ||
| 243 | mem.copy(T, cache[A1.length() + B2.length()..], items[A2.start..A2.end]); | ||
| 244 | mem.copy(T, cache[A1.length()..], items[B2.start..B2.end]); | ||
| 245 | } else if (lessThan(items[B2.start], items[A2.end - 1])) { | ||
| 246 | // these two ranges weren't already in order, so merge them into the cache | ||
| 247 | mergeInto(T, items, A2, B2, lessThan, cache[A1.length()..]); | ||
| 248 | } else { | ||
| 249 | // copy A2 and B2 into the cache in the same order | ||
| 250 | mem.copy(T, cache[A1.length()..], items[A2.start..A2.end]); | ||
| 251 | mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]); | ||
| 252 | } | ||
| 253 | A2 = Range.init(A2.start, B2.end); | ||
| 254 | |||
| 255 | // merge A1 and A2 from the cache into the items | ||
| 256 | const A3 = Range.init(0, A1.length()); | ||
| 257 | const B3 = Range.init(A1.length(), A1.length() + A2.length()); | ||
| 258 | |||
| 259 | if (lessThan(cache[B3.end - 1], cache[A3.start])) { | ||
| 260 | // the two ranges are in reverse order, so copy them in reverse order into the items | ||
| 261 | mem.copy(T, items[A1.start + A2.length()..], cache[A3.start..A3.end]); | ||
| 262 | mem.copy(T, items[A1.start..], cache[B3.start..B3.end]); | ||
| 263 | } else if (lessThan(cache[B3.start], cache[A3.end - 1])) { | ||
| 264 | // these two ranges weren't already in order, so merge them back into the items | ||
| 265 | mergeInto(T, cache[0..], A3, B3, lessThan, items[A1.start..]); | ||
| 266 | } else { | ||
| 267 | // copy A3 and B3 into the items in the same order | ||
| 268 | mem.copy(T, items[A1.start..], cache[A3.start..A3.end]); | ||
| 269 | mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | // we merged two levels at the same time, so we're done with this level already | ||
| 274 | // (iterator.nextLevel() is called again at the bottom of this outer merge loop) | ||
| 275 | _ = iterator.nextLevel(); | ||
| 276 | |||
| 277 | } else { | ||
| 278 | iterator.begin(); | ||
| 279 | while (!iterator.finished()) { | ||
| 280 | var A = iterator.nextRange(); | ||
| 281 | var B = iterator.nextRange(); | ||
| 282 | |||
| 283 | if (lessThan(items[B.end - 1], items[A.start])) { | ||
| 284 | // the two ranges are in reverse order, so a simple rotation should fix it | ||
| 285 | mem.rotate(T, items[A.start..B.end], A.length()); | ||
| 286 | } else if (lessThan(items[B.start], items[A.end - 1])) { | ||
| 287 | // these two ranges weren't already in order, so we'll need to merge them! | ||
| 288 | mem.copy(T, cache[0..], items[A.start..A.end]); | ||
| 289 | mergeExternal(T, items, A, B, lessThan, cache[0..]); | ||
| 290 | } | ||
| 291 | } | ||
| 292 | } | ||
| 293 | } else { | ||
| 294 | // this is where the in-place merge logic starts! | ||
| 295 | // 1. pull out two internal buffers each containing √A unique values | ||
| 296 | // 1a. adjust block_size and buffer_size if we couldn't find enough unique values | ||
| 297 | // 2. loop over the A and B subarrays within this level of the merge sort | ||
| 298 | // 3. break A and B into blocks of size 'block_size' | ||
| 299 | // 4. "tag" each of the A blocks with values from the first internal buffer | ||
| 300 | // 5. roll the A blocks through the B blocks and drop/rotate them where they belong | ||
| 301 | // 6. merge each A block with any B values that follow, using the cache or the second internal buffer | ||
| 302 | // 7. sort the second internal buffer if it exists | ||
| 303 | // 8. redistribute the two internal buffers back into the items | ||
| 304 | |||
| 305 | var block_size: usize = math.sqrt(iterator.length()); | ||
| 306 | var buffer_size = iterator.length()/block_size + 1; | ||
| 307 | |||
| 308 | // as an optimization, we really only need to pull out the internal buffers once for each level of merges | ||
| 309 | // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level | ||
| 310 | var A: Range = undefined; | ||
| 311 | var B: Range = undefined; | ||
| 312 | var index: usize = 0; | ||
| 313 | var last: usize = 0; | ||
| 314 | var count: usize = 0; | ||
| 315 | var find: usize = 0; | ||
| 316 | var start: usize = 0; | ||
| 317 | var pull_index: usize = 0; | ||
| 318 | var pull = []Pull{ | ||
| 319 | Pull {.from = 0, .to = 0, .count = 0, .range = Range.init(0, 0),}, | ||
| 320 | Pull {.from = 0, .to = 0, .count = 0, .range = Range.init(0, 0),}, | ||
| 321 | }; | ||
| 322 | |||
| 323 | var buffer1 = Range.init(0, 0); | ||
| 324 | var buffer2 = Range.init(0, 0); | ||
| 325 | |||
| 326 | // find two internal buffers of size 'buffer_size' each | ||
| 327 | find = buffer_size + buffer_size; | ||
| 328 | var find_separately = false; | ||
| 329 | |||
| 330 | if (block_size <= cache.len) { | ||
| 331 | // if every A block fits into the cache then we won't need the second internal buffer, | ||
| 332 | // so we really only need to find 'buffer_size' unique values | ||
| 333 | find = buffer_size; | ||
| 334 | } else if (find > iterator.length()) { | ||
| 335 | // we can't fit both buffers into the same A or B subarray, so find two buffers separately | ||
| 336 | find = buffer_size; | ||
| 337 | find_separately = true; | ||
| 338 | } | ||
| 339 | |||
| 340 | // we need to find either a single contiguous space containing 2√A unique values (which will be split up into two buffers of size √A each), | ||
| 341 | // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values, | ||
| 342 | // OR if we couldn't find that many unique values, we need the largest possible buffer we can get | ||
| 343 | |||
| 344 | // in the case where it couldn't find a single buffer of at least √A unique values, | ||
| 345 | // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace) | ||
| 346 | iterator.begin(); | ||
| 347 | while (!iterator.finished()) { | ||
| 348 | A = iterator.nextRange(); | ||
| 349 | B = iterator.nextRange(); | ||
| 350 | |||
| 351 | // just store information about where the values will be pulled from and to, | ||
| 352 | // as well as how many values there are, to create the two internal buffers | ||
| 353 | |||
| 354 | // check A for the number of unique values we need to fill an internal buffer | ||
| 355 | // these values will be pulled out to the start of A | ||
| 356 | last = A.start; | ||
| 357 | count = 1; | ||
| 358 | while (count < find) : ({last = index; count += 1;}) { | ||
| 359 | index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count); | ||
| 360 | if (index == A.end) break; | ||
| 361 | } | ||
| 362 | index = last; | ||
| 363 | |||
| 364 | if (count >= buffer_size) { | ||
| 365 | // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer | ||
| 366 | pull[pull_index] = Pull { | ||
| 367 | .range = Range.init(A.start, B.end), | ||
| 368 | .count = count, | ||
| 369 | .from = index, | ||
| 370 | .to = A.start, | ||
| 371 | }; | ||
| 372 | pull_index = 1; | ||
| 373 | |||
| 374 | if (count == buffer_size + buffer_size) { | ||
| 375 | // we were able to find a single contiguous section containing 2√A unique values, | ||
| 376 | // so this section can be used to contain both of the internal buffers we'll need | ||
| 377 | buffer1 = Range.init(A.start, A.start + buffer_size); | ||
| 378 | buffer2 = Range.init(A.start + buffer_size, A.start + count); | ||
| 379 | break; | ||
| 380 | } else if (find == buffer_size + buffer_size) { | ||
| 381 | // we found a buffer that contains at least √A unique values, but did not contain the full 2√A unique values, | ||
| 382 | // so we still need to find a second separate buffer of at least √A unique values | ||
| 383 | buffer1 = Range.init(A.start, A.start + count); | ||
| 384 | find = buffer_size; | ||
| 385 | } else if (block_size <= cache.len) { | ||
| 386 | // we found the first and only internal buffer that we need, so we're done! | ||
| 387 | buffer1 = Range.init(A.start, A.start + count); | ||
| 388 | break; | ||
| 389 | } else if (find_separately) { | ||
| 390 | // found one buffer, but now find the other one | ||
| 391 | buffer1 = Range.init(A.start, A.start + count); | ||
| 392 | find_separately = false; | ||
| 393 | } else { | ||
| 394 | // we found a second buffer in an 'A' subarray containing √A unique values, so we're done! | ||
| 395 | buffer2 = Range.init(A.start, A.start + count); | ||
| 396 | break; | ||
| 397 | } | ||
| 398 | } else if (pull_index == 0 and count > buffer1.length()) { | ||
| 399 | // keep track of the largest buffer we were able to find | ||
| 400 | buffer1 = Range.init(A.start, A.start + count); | ||
| 401 | pull[pull_index] = Pull { | ||
| 402 | .range = Range.init(A.start, B.end), | ||
| 403 | .count = count, | ||
| 404 | .from = index, | ||
| 405 | .to = A.start, | ||
| 406 | }; | ||
| 407 | } | ||
| 408 | |||
| 409 | // check B for the number of unique values we need to fill an internal buffer | ||
| 410 | // these values will be pulled out to the end of B | ||
| 411 | last = B.end - 1; | ||
| 412 | count = 1; | ||
| 413 | while (count < find) : ({last = index - 1; count += 1;}) { | ||
| 414 | index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count); | ||
| 415 | if (index == B.start) break; | ||
| 416 | } | ||
| 417 | index = last; | ||
| 418 | |||
| 419 | if (count >= buffer_size) { | ||
| 420 | // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe | ||
| 421 | pull[pull_index] = Pull { | ||
| 422 | .range = Range.init(A.start, B.end), | ||
| 423 | .count = count, | ||
| 424 | .from = index, | ||
| 425 | .to = B.end, | ||
| 426 | }; | ||
| 427 | pull_index = 1; | ||
| 428 | |||
| 429 | if (count == buffer_size + buffer_size) { | ||
| 430 | // we were able to find a single contiguous section containing 2√A unique values, | ||
| 431 | // so this section can be used to contain both of the internal buffers we'll need | ||
| 432 | buffer1 = Range.init(B.end - count, B.end - buffer_size); | ||
| 433 | buffer2 = Range.init(B.end - buffer_size, B.end); | ||
| 434 | break; | ||
| 435 | } else if (find == buffer_size + buffer_size) { | ||
| 436 | // we found a buffer that contains at least √A unique values, but did not contain the full 2√A unique values, | ||
| 437 | // so we still need to find a second separate buffer of at least √A unique values | ||
| 438 | buffer1 = Range.init(B.end - count, B.end); | ||
| 439 | find = buffer_size; | ||
| 440 | } else if (block_size <= cache.len) { | ||
| 441 | // we found the first and only internal buffer that we need, so we're done! | ||
| 442 | buffer1 = Range.init(B.end - count, B.end); | ||
| 443 | break; | ||
| 444 | } else if (find_separately) { | ||
| 445 | // found one buffer, but now find the other one | ||
| 446 | buffer1 = Range.init(B.end - count, B.end); | ||
| 447 | find_separately = false; | ||
| 448 | } else { | ||
| 449 | // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray, | ||
| 450 | // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2 | ||
| 451 | if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count; | ||
| 452 | |||
| 453 | // we found a second buffer in an 'B' subarray containing √A unique values, so we're done! | ||
| 454 | buffer2 = Range.init(B.end - count, B.end); | ||
| 455 | break; | ||
| 456 | } | ||
| 457 | } else if (pull_index == 0 and count > buffer1.length()) { | ||
| 458 | // keep track of the largest buffer we were able to find | ||
| 459 | buffer1 = Range.init(B.end - count, B.end); | ||
| 460 | pull[pull_index] = Pull { | ||
| 461 | .range = Range.init(A.start, B.end), | ||
| 462 | .count = count, | ||
| 463 | .from = index, | ||
| 464 | .to = B.end, | ||
| 465 | }; | ||
| 466 | } | ||
| 467 | } | ||
| 468 | |||
| 469 | // pull out the two ranges so we can use them as internal buffers | ||
| 470 | pull_index = 0; | ||
| 471 | while (pull_index < 2) : (pull_index += 1) { | ||
| 472 | const length = pull[pull_index].count; | ||
| 473 | |||
| 474 | if (pull[pull_index].to < pull[pull_index].from) { | ||
| 475 | // we're pulling the values out to the left, which means the start of an A subarray | ||
| 476 | index = pull[pull_index].from; | ||
| 477 | count = 1; | ||
| 478 | while (count < length) : (count += 1) { | ||
| 479 | index = findFirstBackward(T, items, items[index - 1], Range.init(pull[pull_index].to, pull[pull_index].from - (count - 1)), lessThan, length - count); | ||
| 480 | const range = Range.init(index + 1, pull[pull_index].from + 1); | ||
| 481 | mem.rotate(T, items[range.start..range.end], range.length() - count); | ||
| 482 | pull[pull_index].from = index + count; | ||
| 483 | } | ||
| 484 | } else if (pull[pull_index].to > pull[pull_index].from) { | ||
| 485 | // we're pulling values out to the right, which means the end of a B subarray | ||
| 486 | index = pull[pull_index].from + 1; | ||
| 487 | count = 1; | ||
| 488 | while (count < length) : (count += 1) { | ||
| 489 | index = findLastForward(T, items, items[index], Range.init(index, pull[pull_index].to), lessThan, length - count); | ||
| 490 | const range = Range.init(pull[pull_index].from, index - 1); | ||
| 491 | mem.rotate(T, items[range.start..range.end], count); | ||
| 492 | pull[pull_index].from = index - 1 - count; | ||
| 493 | } | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | // adjust block_size and buffer_size based on the values we were able to pull out | ||
| 498 | buffer_size = buffer1.length(); | ||
| 499 | block_size = iterator.length()/buffer_size + 1; | ||
| 500 | |||
| 501 | // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks, | ||
| 502 | // so this was originally here to test the math for adjusting block_size above | ||
| 503 | // assert((iterator.length() + 1)/block_size <= buffer_size); | ||
| 504 | |||
| 505 | // now that the two internal buffers have been created, it's time to merge each A+B combination at this level of the merge sort! | ||
| 506 | iterator.begin(); | ||
| 507 | while (!iterator.finished()) { | ||
| 508 | A = iterator.nextRange(); | ||
| 509 | B = iterator.nextRange(); | ||
| 510 | |||
| 511 | // remove any parts of A or B that are being used by the internal buffers | ||
| 512 | start = A.start; | ||
| 513 | if (start == pull[0].range.start) { | ||
| 514 | if (pull[0].from > pull[0].to) { | ||
| 515 | A.start += pull[0].count; | ||
| 516 | |||
| 517 | // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge | ||
| 518 | // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4, | ||
| 519 | // which also only happens when cache.len is small or 0 since it'd otherwise use MergeExternal | ||
| 520 | if (A.length() == 0) continue; | ||
| 521 | } else if (pull[0].from < pull[0].to) { | ||
| 522 | B.end -= pull[0].count; | ||
| 523 | if (B.length() == 0) continue; | ||
| 524 | } | ||
| 525 | } | ||
| 526 | if (start == pull[1].range.start) { | ||
| 527 | if (pull[1].from > pull[1].to) { | ||
| 528 | A.start += pull[1].count; | ||
| 529 | if (A.length() == 0) continue; | ||
| 530 | } else if (pull[1].from < pull[1].to) { | ||
| 531 | B.end -= pull[1].count; | ||
| 532 | if (B.length() == 0) continue; | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 | if (lessThan(items[B.end - 1], items[A.start])) { | ||
| 537 | // the two ranges are in reverse order, so a simple rotation should fix it | ||
| 538 | mem.rotate(T, items[A.start..B.end], A.length()); | ||
| 539 | } else if (lessThan(items[A.end], items[A.end - 1])) { | ||
| 540 | // these two ranges weren't already in order, so we'll need to merge them! | ||
| 541 | var findA: usize = undefined; | ||
| 542 | |||
| 543 | // break the remainder of A into blocks. firstA is the uneven-sized first A block | ||
| 544 | var blockA = Range.init(A.start, A.end); | ||
| 545 | var firstA = Range.init(A.start, A.start + blockA.length() % block_size); | ||
| 546 | |||
| 547 | // swap the first value of each A block with the value in buffer1 | ||
| 548 | var indexA = buffer1.start; | ||
| 549 | index = firstA.end; | ||
| 550 | while (index < blockA.end) : ({indexA += 1; index += block_size;}) { | ||
| 551 | mem.swap(T, &items[indexA], &items[index]); | ||
| 552 | } | ||
| 553 | |||
| 554 | // start rolling the A blocks through the B blocks! | ||
| 555 | // whenever we leave an A block behind, we'll need to merge the previous A block with any B blocks that follow it, so track that information as well | ||
| 556 | var lastA = firstA; | ||
| 557 | var lastB = Range.init(0, 0); | ||
| 558 | var blockB = Range.init(B.start, B.start + math.min(block_size, B.length())); | ||
| 559 | blockA.start += firstA.length(); | ||
| 560 | indexA = buffer1.start; | ||
| 561 | |||
| 562 | // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it | ||
| 563 | // otherwise, if the second buffer is available, block swap the contents into that | ||
| 564 | if (lastA.length() <= cache.len) { | ||
| 565 | mem.copy(T, cache[0..], items[lastA.start..lastA.end]); | ||
| 566 | } else if (buffer2.length() > 0) { | ||
| 567 | blockSwap(T, items, lastA.start, buffer2.start, lastA.length()); | ||
| 568 | } | ||
| 569 | |||
| 570 | if (blockA.length() > 0) { | ||
| 571 | while (true) { | ||
| 572 | // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block, | ||
| 573 | // then drop that minimum A block behind. or if there are no B blocks left then keep dropping the remaining A blocks. | ||
| 574 | if ((lastB.length() > 0 and !lessThan(items[lastB.end - 1], items[indexA])) or blockB.length() == 0) { | ||
| 575 | // figure out where to split the previous B block, and rotate it at the split | ||
| 576 | const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan); | ||
| 577 | const B_remaining = lastB.end - B_split; | ||
| 578 | |||
| 579 | // swap the minimum A block to the beginning of the rolling A blocks | ||
| 580 | var minA = blockA.start; | ||
| 581 | findA = minA + block_size; | ||
| 582 | while (findA < blockA.end) : (findA += block_size) { | ||
| 583 | if (lessThan(items[findA], items[minA])) { | ||
| 584 | minA = findA; | ||
| 585 | } | ||
| 586 | } | ||
| 587 | blockSwap(T, items, blockA.start, minA, block_size); | ||
| 588 | |||
| 589 | // swap the first item of the previous A block back with its original value, which is stored in buffer1 | ||
| 590 | mem.swap(T, &items[blockA.start], &items[indexA]); | ||
| 591 | indexA += 1; | ||
| 592 | |||
| 593 | // locally merge the previous A block with the B values that follow it | ||
| 594 | // if lastA fits into the external cache we'll use that (with MergeExternal), | ||
| 595 | // or if the second internal buffer exists we'll use that (with MergeInternal), | ||
| 596 | // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace) | ||
| 597 | |||
| 598 | if (lastA.length() <= cache.len) { | ||
| 599 | mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]); | ||
| 600 | } else if (buffer2.length() > 0) { | ||
| 601 | mergeInternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, buffer2); | ||
| 602 | } else { | ||
| 603 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan); | ||
| 604 | } | ||
| 605 | |||
| 606 | if (buffer2.length() > 0 or block_size <= cache.len) { | ||
| 607 | // copy the previous A block into the cache or buffer2, since that's where we need it to be when we go to merge it anyway | ||
| 608 | if (block_size <= cache.len) { | ||
| 609 | mem.copy(T, cache[0..], items[blockA.start..blockA.start + block_size]); | ||
| 610 | } else { | ||
| 611 | blockSwap(T, items, blockA.start, buffer2.start, block_size); | ||
| 612 | } | ||
| 613 | |||
| 614 | // this is equivalent to rotating, but faster | ||
| 615 | // the area normally taken up by the A block is either the contents of buffer2, or data we don't need anymore since we memcopied it | ||
| 616 | // either way, we don't need to retain the order of those items, so instead of rotating we can just block swap B to where it belongs | ||
| 617 | blockSwap(T, items, B_split, blockA.start + block_size - B_remaining, B_remaining); | ||
| 618 | } else { | ||
| 619 | // we are unable to use the 'buffer2' trick to speed up the rotation operation since buffer2 doesn't exist, so perform a normal rotation | ||
| 620 | mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split); | ||
| 621 | } | ||
| 622 | |||
| 623 | // update the range for the remaining A blocks, and the range remaining from the B block after it was split | ||
| 624 | lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size); | ||
| 625 | lastB = Range.init(lastA.end, lastA.end + B_remaining); | ||
| 626 | |||
| 627 | // if there are no more A blocks remaining, this step is finished! | ||
| 628 | blockA.start += block_size; | ||
| 629 | if (blockA.length() == 0) | ||
| 630 | break; | ||
| 631 | |||
| 632 | } else if (blockB.length() < block_size) { | ||
| 633 | // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation | ||
| 634 | // the cache is disabled here since it might contain the contents of the previous A block | ||
| 635 | mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start); | ||
| 636 | |||
| 637 | lastB = Range.init(blockA.start, blockA.start + blockB.length()); | ||
| 638 | blockA.start += blockB.length(); | ||
| 639 | blockA.end += blockB.length(); | ||
| 640 | blockB.end = blockB.start; | ||
| 641 | } else { | ||
| 642 | // roll the leftmost A block to the end by swapping it with the next B block | ||
| 643 | blockSwap(T, items, blockA.start, blockB.start, block_size); | ||
| 644 | lastB = Range.init(blockA.start, blockA.start + block_size); | ||
| 645 | |||
| 646 | blockA.start += block_size; | ||
| 647 | blockA.end += block_size; | ||
| 648 | blockB.start += block_size; | ||
| 649 | |||
| 650 | if (blockB.end > B.end - block_size) { | ||
| 651 | blockB.end = B.end; | ||
| 652 | } else { | ||
| 653 | blockB.end += block_size; | ||
| 654 | } | ||
| 655 | } | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 659 | // merge the last A block with the remaining B values | ||
| 660 | if (lastA.length() <= cache.len) { | ||
| 661 | mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]); | ||
| 662 | } else if (buffer2.length() > 0) { | ||
| 663 | mergeInternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, buffer2); | ||
| 664 | } else { | ||
| 665 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B.end), lessThan); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | // when we're finished with this merge step we should have the one or two internal buffers left over, where the second buffer is all jumbled up | ||
| 671 | // insertion sort the second buffer, then redistribute the buffers back into the items using the opposite process used for creating the buffer | ||
| 672 | |||
| 673 | // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort, | ||
| 674 | // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here | ||
| 675 | insertionSort(T, items[buffer2.start..buffer2.end], lessThan); | ||
| 676 | |||
| 677 | pull_index = 0; | ||
| 678 | while (pull_index < 2) : (pull_index += 1) { | ||
| 679 | var unique = pull[pull_index].count * 2; | ||
| 680 | if (pull[pull_index].from > pull[pull_index].to) { | ||
| 681 | // the values were pulled out to the left, so redistribute them back to the right | ||
| 682 | var buffer = Range.init(pull[pull_index].range.start, pull[pull_index].range.start + pull[pull_index].count); | ||
| 683 | while (buffer.length() > 0) { | ||
| 684 | index = findFirstForward(T, items, items[buffer.start], Range.init(buffer.end, pull[pull_index].range.end), lessThan, unique); | ||
| 685 | const amount = index - buffer.end; | ||
| 686 | mem.rotate(T, items[buffer.start..index], buffer.length()); | ||
| 687 | buffer.start += (amount + 1); | ||
| 688 | buffer.end += amount; | ||
| 689 | unique -= 2; | ||
| 690 | } | ||
| 691 | } else if (pull[pull_index].from < pull[pull_index].to) { | ||
| 692 | // the values were pulled out to the right, so redistribute them back to the left | ||
| 693 | var buffer = Range.init(pull[pull_index].range.end - pull[pull_index].count, pull[pull_index].range.end); | ||
| 694 | while (buffer.length() > 0) { | ||
| 695 | index = findLastBackward(T, items, items[buffer.end - 1], Range.init(pull[pull_index].range.start, buffer.start), lessThan, unique); | ||
| 696 | const amount = buffer.start - index; | ||
| 697 | mem.rotate(T, items[index..buffer.end], amount); | ||
| 698 | buffer.start -= amount; | ||
| 699 | buffer.end -= (amount + 1); | ||
| 700 | unique -= 2; | ||
| 701 | } | ||
| 702 | } | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 706 | // double the size of each A and B subarray that will be merged in the next level | ||
| 707 | if (!iterator.nextLevel()) break; | ||
| 23 | } | 708 | } |
| 24 | } | 709 | } |
| 25 | 710 | ||
| 26 | fn quicksort(comptime T: type, array: []T, left: usize, right: usize, comptime cmp: fn(a: &const T, b: &const T)->Cmp) { | 711 | // merge operation without a buffer |
| 27 | var i = left; | 712 | fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)->bool) { |
| 28 | var j = right; | 713 | if (A_arg.length() == 0 or B_arg.length() == 0) return; |
| 29 | const p = (i + j) / 2; | 714 | |
| 715 | // this just repeatedly binary searches into B and rotates A into position. | ||
| 716 | // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here, | ||
| 717 | // but I decided to stick with this because it had better situational performance | ||
| 718 | // | ||
| 719 | // (Hwang and Lin is designed for merging subarrays of very different sizes, | ||
| 720 | // but WikiSort almost always uses subarrays that are roughly the same size) | ||
| 721 | // | ||
| 722 | // normally this is incredibly suboptimal, but this function is only called | ||
| 723 | // when none of the A or B blocks in any subarray contained 2√A unique values, | ||
| 724 | // which places a hard limit on the number of times this will ACTUALLY need | ||
| 725 | // to binary search and rotate. | ||
| 726 | // | ||
| 727 | // according to my analysis the worst case is √A rotations performed on √A items | ||
| 728 | // once the constant factors are removed, which ends up being O(n) | ||
| 729 | // | ||
| 730 | // again, this is NOT a general-purpose solution – it only works well in this case! | ||
| 731 | // kind of like how the O(n^2) insertion sort is used in some places | ||
| 30 | 732 | ||
| 31 | while (i <= j) { | 733 | var A = *A_arg; |
| 32 | while (cmp(array[i], array[p]) == Cmp.Less) { | 734 | var B = *B_arg; |
| 33 | i += 1; | 735 | |
| 736 | while (true) { | ||
| 737 | // find the first place in B where the first item in A needs to be inserted | ||
| 738 | const mid = binaryFirst(T, items, items[A.start], B, lessThan); | ||
| 739 | |||
| 740 | // rotate A into place | ||
| 741 | const amount = mid - A.end; | ||
| 742 | mem.rotate(T, items[A.start..mid], A.length()); | ||
| 743 | if (B.end == mid) break; | ||
| 744 | |||
| 745 | // calculate the new A and B ranges | ||
| 746 | B.start = mid; | ||
| 747 | A = Range.init(A.start + amount, B.start); | ||
| 748 | A.start = binaryLast(T, items, items[A.start], A, lessThan); | ||
| 749 | if (A.length() == 0) break; | ||
| 750 | } | ||
| 751 | } | ||
| 752 | |||
| 753 | // merge operation using an internal buffer | ||
| 754 | fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)->bool, buffer: &const Range) { | ||
| 755 | // whenever we find a value to add to the final array, swap it with the value that's already in that spot | ||
| 756 | // when this algorithm is finished, 'buffer' will contain its original contents, but in a different order | ||
| 757 | var A_count: usize = 0; | ||
| 758 | var B_count: usize = 0; | ||
| 759 | var insert: usize = 0; | ||
| 760 | |||
| 761 | if (B.length() > 0 and A.length() > 0) { | ||
| 762 | while (true) { | ||
| 763 | if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) { | ||
| 764 | mem.swap(T, &items[A.start + insert], &items[buffer.start + A_count]); | ||
| 765 | A_count += 1; | ||
| 766 | insert += 1; | ||
| 767 | if (A_count >= A.length()) break; | ||
| 768 | } else { | ||
| 769 | mem.swap(T, &items[A.start + insert], &items[B.start + B_count]); | ||
| 770 | B_count += 1; | ||
| 771 | insert += 1; | ||
| 772 | if (B_count >= B.length()) break; | ||
| 773 | } | ||
| 34 | } | 774 | } |
| 35 | while (cmp(array[j], array[p]) == Cmp.Greater) { | 775 | } |
| 36 | j -= 1; | 776 | |
| 777 | // swap the remainder of A into the final array | ||
| 778 | blockSwap(T, items, buffer.start + A_count, A.start + insert, A.length() - A_count); | ||
| 779 | } | ||
| 780 | |||
| 781 | fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_size: usize) { | ||
| 782 | var index: usize = 0; | ||
| 783 | while (index < block_size) : (index += 1) { | ||
| 784 | mem.swap(T, &items[start1 + index], &items[start2 + index]); | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | // combine a linear search with a binary search to reduce the number of comparisons in situations | ||
| 789 | // where have some idea as to how many unique values there are and where the next value might be | ||
| 790 | fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool, unique: usize) -> usize { | ||
| 791 | if (range.length() == 0) return range.start; | ||
| 792 | const skip = math.max(range.length()/unique, usize(1)); | ||
| 793 | |||
| 794 | var index = range.start + skip; | ||
| 795 | while (lessThan(items[index - 1], value)) : (index += skip) { | ||
| 796 | if (index >= range.end - skip) { | ||
| 797 | return binaryFirst(T, items, value, Range.init(index, range.end), lessThan); | ||
| 37 | } | 798 | } |
| 38 | if (i <= j) { | 799 | } |
| 39 | const tmp = array[i]; | 800 | |
| 40 | array[i] = array[j]; | 801 | return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan); |
| 41 | array[j] = tmp; | 802 | } |
| 42 | i += 1; | 803 | |
| 43 | if (j > 0) j -= 1; | 804 | fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool, unique: usize) -> usize { |
| 805 | if (range.length() == 0) return range.start; | ||
| 806 | const skip = math.max(range.length()/unique, usize(1)); | ||
| 807 | |||
| 808 | var index = range.end - skip; | ||
| 809 | while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) { | ||
| 810 | if (index < range.start + skip) { | ||
| 811 | return binaryFirst(T, items, value, Range.init(range.start, index), lessThan); | ||
| 44 | } | 812 | } |
| 45 | } | 813 | } |
| 814 | |||
| 815 | return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan); | ||
| 816 | } | ||
| 46 | 817 | ||
| 47 | if (left < j) quicksort(T, array, left, j, cmp); | 818 | fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool, unique: usize) -> usize { |
| 48 | if (i < right) quicksort(T, array, i, right, cmp); | 819 | if (range.length() == 0) return range.start; |
| 820 | const skip = math.max(range.length()/unique, usize(1)); | ||
| 821 | |||
| 822 | var index = range.start + skip; | ||
| 823 | while (!lessThan(value, items[index - 1])) : (index += skip) { | ||
| 824 | if (index >= range.end - skip) { | ||
| 825 | return binaryLast(T, items, value, Range.init(index, range.end), lessThan); | ||
| 826 | } | ||
| 827 | } | ||
| 828 | |||
| 829 | return binaryLast(T, items, value, Range.init(index - skip, index), lessThan); | ||
| 49 | } | 830 | } |
| 50 | 831 | ||
| 51 | pub fn i32asc(a: &const i32, b: &const i32) -> Cmp { | 832 | fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool, unique: usize) -> usize { |
| 52 | return if (*a > *b) Cmp.Greater else if (*a < *b) Cmp.Less else Cmp.Equal | 833 | if (range.length() == 0) return range.start; |
| 834 | const skip = math.max(range.length()/unique, usize(1)); | ||
| 835 | |||
| 836 | var index = range.end - skip; | ||
| 837 | while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) { | ||
| 838 | if (index < range.start + skip) { | ||
| 839 | return binaryLast(T, items, value, Range.init(range.start, index), lessThan); | ||
| 840 | } | ||
| 841 | } | ||
| 842 | |||
| 843 | return binaryLast(T, items, value, Range.init(index, index + skip), lessThan); | ||
| 53 | } | 844 | } |
| 54 | 845 | ||
| 55 | pub fn i32desc(a: &const i32, b: &const i32) -> Cmp { | 846 | fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool) -> usize { |
| 56 | reverse(i32asc(a, b)) | 847 | var start = range.start; |
| 848 | var end = range.end - 1; | ||
| 849 | if (range.start >= range.end) return range.end; | ||
| 850 | while (start < end) { | ||
| 851 | const mid = start + (end - start)/2; | ||
| 852 | if (lessThan(items[mid], value)) { | ||
| 853 | start = mid + 1; | ||
| 854 | } else { | ||
| 855 | end = mid; | ||
| 856 | } | ||
| 857 | } | ||
| 858 | if (start == range.end - 1 and lessThan(items[start], value)) { | ||
| 859 | start += 1; | ||
| 860 | } | ||
| 861 | return start; | ||
| 57 | } | 862 | } |
| 58 | 863 | ||
| 59 | pub fn u8asc(a: &const u8, b: &const u8) -> Cmp { | 864 | fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool) -> usize { |
| 60 | if (*a > *b) Cmp.Greater else if (*a < *b) Cmp.Less else Cmp.Equal | 865 | var start = range.start; |
| 866 | var end = range.end - 1; | ||
| 867 | if (range.start >= range.end) return range.end; | ||
| 868 | while (start < end) { | ||
| 869 | const mid = start + (end - start)/2; | ||
| 870 | if (!lessThan(value, items[mid])) { | ||
| 871 | start = mid + 1; | ||
| 872 | } else { | ||
| 873 | end = mid; | ||
| 874 | } | ||
| 875 | } | ||
| 876 | if (start == range.end - 1 and !lessThan(value, items[start])) { | ||
| 877 | start += 1; | ||
| 878 | } | ||
| 879 | return start; | ||
| 61 | } | 880 | } |
| 62 | 881 | ||
| 63 | pub fn u8desc(a: &const u8, b: &const u8) -> Cmp { | 882 | fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)->bool, into: []T) { |
| 64 | reverse(u8asc(a, b)) | 883 | var A_index: usize = A.start; |
| 884 | var B_index: usize = B.start; | ||
| 885 | const A_last = A.end; | ||
| 886 | const B_last = B.end; | ||
| 887 | var insert_index: usize = 0; | ||
| 888 | |||
| 889 | while (true) { | ||
| 890 | if (!lessThan(from[B_index], from[A_index])) { | ||
| 891 | into[insert_index] = from[A_index]; | ||
| 892 | A_index += 1; | ||
| 893 | insert_index += 1; | ||
| 894 | if (A_index == A_last) { | ||
| 895 | // copy the remainder of B into the final array | ||
| 896 | mem.copy(T, into[insert_index..], from[B_index..B_last]); | ||
| 897 | break; | ||
| 898 | } | ||
| 899 | } else { | ||
| 900 | into[insert_index] = from[B_index]; | ||
| 901 | B_index += 1; | ||
| 902 | insert_index += 1; | ||
| 903 | if (B_index == B_last) { | ||
| 904 | // copy the remainder of A into the final array | ||
| 905 | mem.copy(T, into[insert_index..], from[A_index..A_last]); | ||
| 906 | break; | ||
| 907 | } | ||
| 908 | } | ||
| 909 | } | ||
| 65 | } | 910 | } |
| 66 | 911 | ||
| 67 | fn reverse(was: Cmp) -> Cmp { | 912 | fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)->bool, cache: []T) { |
| 68 | if (was == Cmp.Greater) Cmp.Less else if (was == Cmp.Less) Cmp.Greater else Cmp.Equal | 913 | // A fits into the cache, so use that instead of the internal buffer |
| 914 | var A_index: usize = 0; | ||
| 915 | var B_index: usize = B.start; | ||
| 916 | var insert_index: usize = A.start; | ||
| 917 | const A_last = A.length(); | ||
| 918 | const B_last = B.end; | ||
| 919 | |||
| 920 | if (B.length() > 0 and A.length() > 0) { | ||
| 921 | while (true) { | ||
| 922 | if (!lessThan(items[B_index], cache[A_index])) { | ||
| 923 | items[insert_index] = cache[A_index]; | ||
| 924 | A_index += 1; | ||
| 925 | insert_index += 1; | ||
| 926 | if (A_index == A_last) break; | ||
| 927 | } else { | ||
| 928 | items[insert_index] = items[B_index]; | ||
| 929 | B_index += 1; | ||
| 930 | insert_index += 1; | ||
| 931 | if (B_index == B_last) break; | ||
| 932 | } | ||
| 933 | } | ||
| 934 | } | ||
| 935 | |||
| 936 | // copy the remainder of A into the final array | ||
| 937 | mem.copy(T, items[insert_index..], cache[A_index..A_last]); | ||
| 938 | } | ||
| 939 | |||
| 940 | fn swap(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)->bool, order: &[8]u8, x: usize, y: usize) { | ||
| 941 | if (lessThan(items[y], items[x]) or | ||
| 942 | ((*order)[x] > (*order)[y] and !lessThan(items[x], items[y]))) | ||
| 943 | { | ||
| 944 | mem.swap(T, &items[x], &items[y]); | ||
| 945 | mem.swap(u8, &(*order)[x], &(*order)[y]); | ||
| 946 | } | ||
| 947 | } | ||
| 948 | |||
| 949 | fn i32asc(lhs: &const i32, rhs: &const i32) -> bool { | ||
| 950 | return *lhs < *rhs; | ||
| 69 | } | 951 | } |
| 70 | 952 | ||
| 71 | // --------------------------------------- | 953 | fn i32desc(lhs: &const i32, rhs: &const i32) -> bool { |
| 72 | // tests | 954 | return *rhs < *lhs; |
| 955 | } | ||
| 956 | |||
| 957 | fn u8asc(lhs: &const u8, rhs: &const u8) -> bool { | ||
| 958 | return *lhs < *rhs; | ||
| 959 | } | ||
| 960 | |||
| 961 | fn u8desc(lhs: &const u8, rhs: &const u8) -> bool { | ||
| 962 | return *rhs < *lhs; | ||
| 963 | } | ||
| 73 | 964 | ||
| 74 | test "stable sort" { | 965 | test "stable sort" { |
| 75 | testStableSort(); | 966 | testStableSort(); |
| ... | @@ -113,7 +1004,7 @@ fn testStableSort() { | ... | @@ -113,7 +1004,7 @@ fn testStableSort() { |
| 113 | }, | 1004 | }, |
| 114 | }; | 1005 | }; |
| 115 | for (cases) |*case| { | 1006 | for (cases) |*case| { |
| 116 | sort_stable(IdAndValue, (*case)[0..], cmpByValue); | 1007 | insertionSort(IdAndValue, (*case)[0..], cmpByValue); |
| 117 | for (*case) |item, i| { | 1008 | for (*case) |item, i| { |
| 118 | assert(item.id == expected[i].id); | 1009 | assert(item.id == expected[i].id); |
| 119 | assert(item.value == expected[i].value); | 1010 | assert(item.value == expected[i].value); |
| ... | @@ -121,14 +1012,19 @@ fn testStableSort() { | ... | @@ -121,14 +1012,19 @@ fn testStableSort() { |
| 121 | } | 1012 | } |
| 122 | } | 1013 | } |
| 123 | const IdAndValue = struct { | 1014 | const IdAndValue = struct { |
| 124 | id: i32, | 1015 | id: usize, |
| 125 | value: i32, | 1016 | value: i32, |
| 126 | }; | 1017 | }; |
| 127 | fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> Cmp { | 1018 | fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> bool { |
| 128 | return i32asc(a.value, b.value); | 1019 | return i32asc(a.value, b.value); |
| 129 | } | 1020 | } |
| 130 | 1021 | ||
| 131 | test "testSort" { | 1022 | test "std.sort" { |
| 1023 | if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) { | ||
| 1024 | // TODO get this test passing | ||
| 1025 | // https://github.com/zig-lang/zig/issues/537 | ||
| 1026 | return; | ||
| 1027 | } | ||
| 132 | const u8cases = [][]const []const u8 { | 1028 | const u8cases = [][]const []const u8 { |
| 133 | [][]const u8{"", ""}, | 1029 | [][]const u8{"", ""}, |
| 134 | [][]const u8{"a", "a"}, | 1030 | [][]const u8{"a", "a"}, |
| ... | @@ -164,7 +1060,12 @@ test "testSort" { | ... | @@ -164,7 +1060,12 @@ test "testSort" { |
| 164 | } | 1060 | } |
| 165 | } | 1061 | } |
| 166 | 1062 | ||
| 167 | test "testSortDesc" { | 1063 | test "std.sort descending" { |
| 1064 | if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) { | ||
| 1065 | // TODO get this test passing | ||
| 1066 | // https://github.com/zig-lang/zig/issues/537 | ||
| 1067 | return; | ||
| 1068 | } | ||
| 168 | const rev_cases = [][]const []const i32 { | 1069 | const rev_cases = [][]const []const i32 { |
| 169 | [][]const i32{[]i32{}, []i32{}}, | 1070 | [][]const i32{[]i32{}, []i32{}}, |
| 170 | [][]const i32{[]i32{1}, []i32{1}}, | 1071 | [][]const i32{[]i32{1}, []i32{1}}, |
| ... | @@ -182,3 +1083,74 @@ test "testSortDesc" { | ... | @@ -182,3 +1083,74 @@ test "testSortDesc" { |
| 182 | assert(mem.eql(i32, slice, case[1])); | 1083 | assert(mem.eql(i32, slice, case[1])); |
| 183 | } | 1084 | } |
| 184 | } | 1085 | } |
| 1086 | |||
| 1087 | test "another sort case" { | ||
| 1088 | if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) { | ||
| 1089 | // TODO get this test passing | ||
| 1090 | // https://github.com/zig-lang/zig/issues/537 | ||
| 1091 | return; | ||
| 1092 | } | ||
| 1093 | var arr = []i32{ 5, 3, 1, 2, 4 }; | ||
| 1094 | sort(i32, arr[0..], i32asc); | ||
| 1095 | |||
| 1096 | assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 })); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | test "sort fuzz testing" { | ||
| 1100 | if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) { | ||
| 1101 | // TODO get this test passing | ||
| 1102 | // https://github.com/zig-lang/zig/issues/537 | ||
| 1103 | return; | ||
| 1104 | } | ||
| 1105 | var rng = std.rand.Rand.init(0x12345678); | ||
| 1106 | const test_case_count = 10; | ||
| 1107 | var i: usize = 0; | ||
| 1108 | while (i < test_case_count) : (i += 1) { | ||
| 1109 | fuzzTest(&rng); | ||
| 1110 | } | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | var fixed_buffer_mem: [100 * 1024]u8 = undefined; | ||
| 1114 | |||
| 1115 | fn fuzzTest(rng: &std.rand.Rand) { | ||
| 1116 | const array_size = rng.range(usize, 0, 1000); | ||
| 1117 | var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]); | ||
| 1118 | var array = %%fixed_allocator.allocator.alloc(IdAndValue, array_size); | ||
| 1119 | // populate with random data | ||
| 1120 | for (array) |*item, index| { | ||
| 1121 | item.id = index; | ||
| 1122 | item.value = rng.range(i32, 0, 100); | ||
| 1123 | } | ||
| 1124 | sort(IdAndValue, array, cmpByValue); | ||
| 1125 | |||
| 1126 | var index: usize = 1; | ||
| 1127 | while (index < array.len) : (index += 1) { | ||
| 1128 | if (array[index].value == array[index - 1].value) { | ||
| 1129 | assert(array[index].id > array[index - 1].id); | ||
| 1130 | } else { | ||
| 1131 | assert(array[index].value > array[index - 1].value); | ||
| 1132 | } | ||
| 1133 | } | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)->bool) -> T { | ||
| 1137 | var i: usize = 0; | ||
| 1138 | var smallest = items[0]; | ||
| 1139 | for (items[1..]) |item| { | ||
| 1140 | if (lessThan(item, smallest)) { | ||
| 1141 | smallest = item; | ||
| 1142 | } | ||
| 1143 | } | ||
| 1144 | return smallest; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | pub fn max(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)->bool) -> T { | ||
| 1148 | var i: usize = 0; | ||
| 1149 | var biggest = items[0]; | ||
| 1150 | for (items[1..]) |item| { | ||
| 1151 | if (lessThan(biggest, item)) { | ||
| 1152 | biggest = item; | ||
| 1153 | } | ||
| 1154 | } | ||
| 1155 | return biggest; | ||
| 1156 | } |
std/special/bootstrap.zig+15-25| ... | @@ -5,20 +5,20 @@ const root = @import("@root"); | ... | @@ -5,20 +5,20 @@ const root = @import("@root"); |
| 5 | const std = @import("std"); | 5 | const std = @import("std"); |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | 7 | ||
| 8 | const is_windows = builtin.os == builtin.Os.windows; | ||
| 9 | const want_main_symbol = builtin.link_libc; | ||
| 10 | const want_start_symbol = !want_main_symbol and !is_windows; | ||
| 11 | const want_WinMainCRTStartup = is_windows and !builtin.link_libc; | ||
| 12 | |||
| 13 | var argc_ptr: &usize = undefined; | 8 | var argc_ptr: &usize = undefined; |
| 14 | 9 | ||
| 15 | 10 | comptime { | |
| 16 | export nakedcc fn _start() -> noreturn { | 11 | const strong_linkage = builtin.GlobalLinkage.Strong; |
| 17 | if (!want_start_symbol) { | 12 | if (builtin.link_libc) { |
| 18 | @setGlobalLinkage(_start, builtin.GlobalLinkage.Internal); | 13 | @export("main", main, strong_linkage); |
| 19 | unreachable; | 14 | } else if (builtin.os == builtin.Os.windows) { |
| 15 | @export("WinMainCRTStartup", WinMainCRTStartup, strong_linkage); | ||
| 16 | } else { | ||
| 17 | @export("_start", _start, strong_linkage); | ||
| 20 | } | 18 | } |
| 19 | } | ||
| 21 | 20 | ||
| 21 | nakedcc fn _start() -> noreturn { | ||
| 22 | switch (builtin.arch) { | 22 | switch (builtin.arch) { |
| 23 | builtin.Arch.x86_64 => { | 23 | builtin.Arch.x86_64 => { |
| 24 | argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize)); | 24 | argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize)); |
| ... | @@ -28,17 +28,14 @@ export nakedcc fn _start() -> noreturn { | ... | @@ -28,17 +28,14 @@ export nakedcc fn _start() -> noreturn { |
| 28 | }, | 28 | }, |
| 29 | else => @compileError("unsupported arch"), | 29 | else => @compileError("unsupported arch"), |
| 30 | } | 30 | } |
| 31 | posixCallMainAndExit() | 31 | // If LLVM inlines stack variables into _start, they will overwrite |
| 32 | // the command line argument data. | ||
| 33 | @noInlineCall(posixCallMainAndExit); | ||
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | export fn WinMainCRTStartup() -> noreturn { | 36 | extern fn WinMainCRTStartup() -> noreturn { |
| 35 | if (!want_WinMainCRTStartup) { | ||
| 36 | @setGlobalLinkage(WinMainCRTStartup, builtin.GlobalLinkage.Internal); | ||
| 37 | unreachable; | ||
| 38 | } | ||
| 39 | @setAlignStack(16); | 37 | @setAlignStack(16); |
| 40 | 38 | ||
| 41 | std.debug.user_main_fn = root.main; | ||
| 42 | root.main() %% std.os.windows.ExitProcess(1); | 39 | root.main() %% std.os.windows.ExitProcess(1); |
| 43 | std.os.windows.ExitProcess(0); | 40 | std.os.windows.ExitProcess(0); |
| 44 | } | 41 | } |
| ... | @@ -58,17 +55,10 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { | ... | @@ -58,17 +55,10 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { |
| 58 | while (envp[env_count] != null) : (env_count += 1) {} | 55 | while (envp[env_count] != null) : (env_count += 1) {} |
| 59 | std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count]; | 56 | std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count]; |
| 60 | 57 | ||
| 61 | std.debug.user_main_fn = root.main; | ||
| 62 | |||
| 63 | return root.main(); | 58 | return root.main(); |
| 64 | } | 59 | } |
| 65 | 60 | ||
| 66 | export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { | 61 | extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { |
| 67 | if (!want_main_symbol) { | ||
| 68 | @setGlobalLinkage(main, builtin.GlobalLinkage.Internal); | ||
| 69 | unreachable; | ||
| 70 | } | ||
| 71 | |||
| 72 | callMain(usize(c_argc), c_argv, c_envp) %% return 1; | 62 | callMain(usize(c_argc), c_argv, c_envp) %% return 1; |
| 73 | return 0; | 63 | return 0; |
| 74 | } | 64 | } |
std/special/bootstrap_lib.zig+5-1| ... | @@ -2,7 +2,11 @@ | ... | @@ -2,7 +2,11 @@ |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | 4 | ||
| 5 | export stdcallcc fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD, | 5 | comptime { |
| 6 | @export("_DllMainCRTStartup", _DllMainCRTStartup); | ||
| 7 | } | ||
| 8 | |||
| 9 | stdcallcc fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD, | ||
| 6 | lpReserved: std.os.windows.LPVOID) -> std.os.windows.BOOL | 10 | lpReserved: std.os.windows.LPVOID) -> std.os.windows.BOOL |
| 7 | { | 11 | { |
| 8 | return std.os.windows.TRUE; | 12 | return std.os.windows.TRUE; |
std/special/build_runner.zig+6-10| ... | @@ -45,21 +45,17 @@ pub fn main() -> %void { | ... | @@ -45,21 +45,17 @@ pub fn main() -> %void { |
| 45 | 45 | ||
| 46 | var stderr_file = io.getStdErr(); | 46 | var stderr_file = io.getStdErr(); |
| 47 | var stderr_file_stream: io.FileOutStream = undefined; | 47 | var stderr_file_stream: io.FileOutStream = undefined; |
| 48 | var stderr_stream: %&io.OutStream = if (stderr_file) |*f| { | 48 | var stderr_stream: %&io.OutStream = if (stderr_file) |*f| x: { |
| 49 | stderr_file_stream = io.FileOutStream.init(f); | 49 | stderr_file_stream = io.FileOutStream.init(f); |
| 50 | &stderr_file_stream.stream | 50 | break :x &stderr_file_stream.stream; |
| 51 | } else |err| { | 51 | } else |err| err; |
| 52 | err | ||
| 53 | }; | ||
| 54 | 52 | ||
| 55 | var stdout_file = io.getStdOut(); | 53 | var stdout_file = io.getStdOut(); |
| 56 | var stdout_file_stream: io.FileOutStream = undefined; | 54 | var stdout_file_stream: io.FileOutStream = undefined; |
| 57 | var stdout_stream: %&io.OutStream = if (stdout_file) |*f| { | 55 | var stdout_stream: %&io.OutStream = if (stdout_file) |*f| x: { |
| 58 | stdout_file_stream = io.FileOutStream.init(f); | 56 | stdout_file_stream = io.FileOutStream.init(f); |
| 59 | &stdout_file_stream.stream | 57 | break :x &stdout_file_stream.stream; |
| 60 | } else |err| { | 58 | } else |err| err; |
| 61 | err | ||
| 62 | }; | ||
| 63 | 59 | ||
| 64 | while (arg_it.next(allocator)) |err_or_arg| { | 60 | while (arg_it.next(allocator)) |err_or_arg| { |
| 65 | const arg = %return unwrapArg(err_or_arg); | 61 | const arg = %return unwrapArg(err_or_arg); |
std/special/builtin.zig+14-13| ... | @@ -35,25 +35,26 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { | ... | @@ -35,25 +35,26 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { |
| 35 | (??dest)[index] = (??src)[index]; | 35 | (??dest)[index] = (??src)[index]; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | export fn __stack_chk_fail() -> noreturn { | 38 | comptime { |
| 39 | if (builtin.mode == builtin.Mode.ReleaseFast or builtin.os == builtin.Os.windows) { | 39 | if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) { |
| 40 | @setGlobalLinkage(__stack_chk_fail, builtin.GlobalLinkage.Internal); | 40 | @export("__stack_chk_fail", __stack_chk_fail, builtin.GlobalLinkage.Strong); |
| 41 | unreachable; | ||
| 42 | } | 41 | } |
| 42 | } | ||
| 43 | extern fn __stack_chk_fail() -> noreturn { | ||
| 43 | @panic("stack smashing detected"); | 44 | @panic("stack smashing detected"); |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | const math = @import("../math/index.zig"); | 47 | const math = @import("../math/index.zig"); |
| 47 | 48 | ||
| 48 | export fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) } | 49 | export fn fmodf(x: f32, y: f32) -> f32 { return generic_fmod(f32, x, y); } |
| 49 | export fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) } | 50 | export fn fmod(x: f64, y: f64) -> f64 { return generic_fmod(f64, x, y); } |
| 50 | 51 | ||
| 51 | // TODO add intrinsics for these (and probably the double version too) | 52 | // TODO add intrinsics for these (and probably the double version too) |
| 52 | // and have the math stuff use the intrinsic. same as @mod and @rem | 53 | // and have the math stuff use the intrinsic. same as @mod and @rem |
| 53 | export fn floorf(x: f32) -> f32 { math.floor(x) } | 54 | export fn floorf(x: f32) -> f32 { return math.floor(x); } |
| 54 | export fn ceilf(x: f32) -> f32 { math.ceil(x) } | 55 | export fn ceilf(x: f32) -> f32 { return math.ceil(x); } |
| 55 | export fn floor(x: f64) -> f64 { math.floor(x) } | 56 | export fn floor(x: f64) -> f64 { return math.floor(x); } |
| 56 | export fn ceil(x: f64) -> f64 { math.ceil(x) } | 57 | export fn ceil(x: f64) -> f64 { return math.ceil(x); } |
| 57 | 58 | ||
| 58 | fn generic_fmod(comptime T: type, x: T, y: T) -> T { | 59 | fn generic_fmod(comptime T: type, x: T, y: T) -> T { |
| 59 | @setDebugSafety(this, false); | 60 | @setDebugSafety(this, false); |
| ... | @@ -83,7 +84,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { | ... | @@ -83,7 +84,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { |
| 83 | // normalize x and y | 84 | // normalize x and y |
| 84 | if (ex == 0) { | 85 | if (ex == 0) { |
| 85 | i = ux << exp_bits; | 86 | i = ux << exp_bits; |
| 86 | while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<= 1}) {} | 87 | while (i >> bits_minus_1 == 0) : (b: {ex -= 1; break :b i <<= 1;}) {} |
| 87 | ux <<= log2uint(@bitCast(u32, -ex + 1)); | 88 | ux <<= log2uint(@bitCast(u32, -ex + 1)); |
| 88 | } else { | 89 | } else { |
| 89 | ux &= @maxValue(uint) >> exp_bits; | 90 | ux &= @maxValue(uint) >> exp_bits; |
| ... | @@ -91,7 +92,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { | ... | @@ -91,7 +92,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { |
| 91 | } | 92 | } |
| 92 | if (ey == 0) { | 93 | if (ey == 0) { |
| 93 | i = uy << exp_bits; | 94 | i = uy << exp_bits; |
| 94 | while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<= 1}) {} | 95 | while (i >> bits_minus_1 == 0) : (b: {ey -= 1; break :b i <<= 1;}) {} |
| 95 | uy <<= log2uint(@bitCast(u32, -ey + 1)); | 96 | uy <<= log2uint(@bitCast(u32, -ey + 1)); |
| 96 | } else { | 97 | } else { |
| 97 | uy &= @maxValue(uint) >> exp_bits; | 98 | uy &= @maxValue(uint) >> exp_bits; |
| ... | @@ -114,7 +115,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { | ... | @@ -114,7 +115,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { |
| 114 | return 0 * x; | 115 | return 0 * x; |
| 115 | ux = i; | 116 | ux = i; |
| 116 | } | 117 | } |
| 117 | while (ux >> digits == 0) : ({ux <<= 1; ex -= 1}) {} | 118 | while (ux >> digits == 0) : (b: {ux <<= 1; break :b ex -= 1;}) {} |
| 118 | 119 | ||
| 119 | // scale result up | 120 | // scale result up |
| 120 | if (ex > 0) { | 121 | if (ex > 0) { |
std/special/compiler_rt/aulldiv.zig+54-65| ... | @@ -1,66 +1,55 @@ | ... | @@ -1,66 +1,55 @@ |
| 1 | const builtin = @import("builtin"); | 1 | pub nakedcc fn _aulldiv() { |
| 2 | const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; | 2 | @setDebugSafety(this, false); |
| 3 | const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; | 3 | asm volatile ( |
| 4 | 4 | \\.intel_syntax noprefix | |
| 5 | export nakedcc fn _aulldiv() { | 5 | \\ |
| 6 | if (is_win32) { | 6 | \\ push ebx |
| 7 | @setDebugSafety(this, false); | 7 | \\ push esi |
| 8 | @setGlobalLinkage(_aulldiv, linkage); | 8 | \\ mov eax,dword ptr [esp+18h] |
| 9 | asm volatile ( | 9 | \\ or eax,eax |
| 10 | \\.intel_syntax noprefix | 10 | \\ jne L1 |
| 11 | \\ | 11 | \\ mov ecx,dword ptr [esp+14h] |
| 12 | \\ push ebx | 12 | \\ mov eax,dword ptr [esp+10h] |
| 13 | \\ push esi | 13 | \\ xor edx,edx |
| 14 | \\ mov eax,dword ptr [esp+18h] | 14 | \\ div ecx |
| 15 | \\ or eax,eax | 15 | \\ mov ebx,eax |
| 16 | \\ jne L1 | 16 | \\ mov eax,dword ptr [esp+0Ch] |
| 17 | \\ mov ecx,dword ptr [esp+14h] | 17 | \\ div ecx |
| 18 | \\ mov eax,dword ptr [esp+10h] | 18 | \\ mov edx,ebx |
| 19 | \\ xor edx,edx | 19 | \\ jmp L2 |
| 20 | \\ div ecx | 20 | \\ L1: |
| 21 | \\ mov ebx,eax | 21 | \\ mov ecx,eax |
| 22 | \\ mov eax,dword ptr [esp+0Ch] | 22 | \\ mov ebx,dword ptr [esp+14h] |
| 23 | \\ div ecx | 23 | \\ mov edx,dword ptr [esp+10h] |
| 24 | \\ mov edx,ebx | 24 | \\ mov eax,dword ptr [esp+0Ch] |
| 25 | \\ jmp L2 | 25 | \\ L3: |
| 26 | \\ L1: | 26 | \\ shr ecx,1 |
| 27 | \\ mov ecx,eax | 27 | \\ rcr ebx,1 |
| 28 | \\ mov ebx,dword ptr [esp+14h] | 28 | \\ shr edx,1 |
| 29 | \\ mov edx,dword ptr [esp+10h] | 29 | \\ rcr eax,1 |
| 30 | \\ mov eax,dword ptr [esp+0Ch] | 30 | \\ or ecx,ecx |
| 31 | \\ L3: | 31 | \\ jne L3 |
| 32 | \\ shr ecx,1 | 32 | \\ div ebx |
| 33 | \\ rcr ebx,1 | 33 | \\ mov esi,eax |
| 34 | \\ shr edx,1 | 34 | \\ mul dword ptr [esp+18h] |
| 35 | \\ rcr eax,1 | 35 | \\ mov ecx,eax |
| 36 | \\ or ecx,ecx | 36 | \\ mov eax,dword ptr [esp+14h] |
| 37 | \\ jne L3 | 37 | \\ mul esi |
| 38 | \\ div ebx | 38 | \\ add edx,ecx |
| 39 | \\ mov esi,eax | 39 | \\ jb L4 |
| 40 | \\ mul dword ptr [esp+18h] | 40 | \\ cmp edx,dword ptr [esp+10h] |
| 41 | \\ mov ecx,eax | 41 | \\ ja L4 |
| 42 | \\ mov eax,dword ptr [esp+14h] | 42 | \\ jb L5 |
| 43 | \\ mul esi | 43 | \\ cmp eax,dword ptr [esp+0Ch] |
| 44 | \\ add edx,ecx | 44 | \\ jbe L5 |
| 45 | \\ jb L4 | 45 | \\ L4: |
| 46 | \\ cmp edx,dword ptr [esp+10h] | 46 | \\ dec esi |
| 47 | \\ ja L4 | 47 | \\ L5: |
| 48 | \\ jb L5 | 48 | \\ xor edx,edx |
| 49 | \\ cmp eax,dword ptr [esp+0Ch] | 49 | \\ mov eax,esi |
| 50 | \\ jbe L5 | 50 | \\ L2: |
| 51 | \\ L4: | 51 | \\ pop esi |
| 52 | \\ dec esi | 52 | \\ pop ebx |
| 53 | \\ L5: | 53 | \\ ret 10h |
| 54 | \\ xor edx,edx | 54 | ); |
| 55 | \\ mov eax,esi | ||
| 56 | \\ L2: | ||
| 57 | \\ pop esi | ||
| 58 | \\ pop ebx | ||
| 59 | \\ ret 10h | ||
| 60 | ); | ||
| 61 | unreachable; | ||
| 62 | } | ||
| 63 | |||
| 64 | @setGlobalLinkage(_aulldiv, builtin.GlobalLinkage.Internal); | ||
| 65 | unreachable; | ||
| 66 | } | 55 | } |
std/special/compiler_rt/aullrem.zig+55-66| ... | @@ -1,67 +1,56 @@ | ... | @@ -1,67 +1,56 @@ |
| 1 | const builtin = @import("builtin"); | 1 | pub nakedcc fn _aullrem() { |
| 2 | const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; | 2 | @setDebugSafety(this, false); |
| 3 | const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; | 3 | asm volatile ( |
| 4 | 4 | \\.intel_syntax noprefix | |
| 5 | export nakedcc fn _aullrem() { | 5 | \\ |
| 6 | if (is_win32) { | 6 | \\ push ebx |
| 7 | @setDebugSafety(this, false); | 7 | \\ mov eax,dword ptr [esp+14h] |
| 8 | @setGlobalLinkage(_aullrem, linkage); | 8 | \\ or eax,eax |
| 9 | asm volatile ( | 9 | \\ jne L1a |
| 10 | \\.intel_syntax noprefix | 10 | \\ mov ecx,dword ptr [esp+10h] |
| 11 | \\ | 11 | \\ mov eax,dword ptr [esp+0Ch] |
| 12 | \\ push ebx | 12 | \\ xor edx,edx |
| 13 | \\ mov eax,dword ptr [esp+14h] | 13 | \\ div ecx |
| 14 | \\ or eax,eax | 14 | \\ mov eax,dword ptr [esp+8] |
| 15 | \\ jne L1a | 15 | \\ div ecx |
| 16 | \\ mov ecx,dword ptr [esp+10h] | 16 | \\ mov eax,edx |
| 17 | \\ mov eax,dword ptr [esp+0Ch] | 17 | \\ xor edx,edx |
| 18 | \\ xor edx,edx | 18 | \\ jmp L2a |
| 19 | \\ div ecx | 19 | \\ L1a: |
| 20 | \\ mov eax,dword ptr [esp+8] | 20 | \\ mov ecx,eax |
| 21 | \\ div ecx | 21 | \\ mov ebx,dword ptr [esp+10h] |
| 22 | \\ mov eax,edx | 22 | \\ mov edx,dword ptr [esp+0Ch] |
| 23 | \\ xor edx,edx | 23 | \\ mov eax,dword ptr [esp+8] |
| 24 | \\ jmp L2a | 24 | \\ L3a: |
| 25 | \\ L1a: | 25 | \\ shr ecx,1 |
| 26 | \\ mov ecx,eax | 26 | \\ rcr ebx,1 |
| 27 | \\ mov ebx,dword ptr [esp+10h] | 27 | \\ shr edx,1 |
| 28 | \\ mov edx,dword ptr [esp+0Ch] | 28 | \\ rcr eax,1 |
| 29 | \\ mov eax,dword ptr [esp+8] | 29 | \\ or ecx,ecx |
| 30 | \\ L3a: | 30 | \\ jne L3a |
| 31 | \\ shr ecx,1 | 31 | \\ div ebx |
| 32 | \\ rcr ebx,1 | 32 | \\ mov ecx,eax |
| 33 | \\ shr edx,1 | 33 | \\ mul dword ptr [esp+14h] |
| 34 | \\ rcr eax,1 | 34 | \\ xchg eax,ecx |
| 35 | \\ or ecx,ecx | 35 | \\ mul dword ptr [esp+10h] |
| 36 | \\ jne L3a | 36 | \\ add edx,ecx |
| 37 | \\ div ebx | 37 | \\ jb L4a |
| 38 | \\ mov ecx,eax | 38 | \\ cmp edx,dword ptr [esp+0Ch] |
| 39 | \\ mul dword ptr [esp+14h] | 39 | \\ ja L4a |
| 40 | \\ xchg eax,ecx | 40 | \\ jb L5a |
| 41 | \\ mul dword ptr [esp+10h] | 41 | \\ cmp eax,dword ptr [esp+8] |
| 42 | \\ add edx,ecx | 42 | \\ jbe L5a |
| 43 | \\ jb L4a | 43 | \\ L4a: |
| 44 | \\ cmp edx,dword ptr [esp+0Ch] | 44 | \\ sub eax,dword ptr [esp+10h] |
| 45 | \\ ja L4a | 45 | \\ sbb edx,dword ptr [esp+14h] |
| 46 | \\ jb L5a | 46 | \\ L5a: |
| 47 | \\ cmp eax,dword ptr [esp+8] | 47 | \\ sub eax,dword ptr [esp+8] |
| 48 | \\ jbe L5a | 48 | \\ sbb edx,dword ptr [esp+0Ch] |
| 49 | \\ L4a: | 49 | \\ neg edx |
| 50 | \\ sub eax,dword ptr [esp+10h] | 50 | \\ neg eax |
| 51 | \\ sbb edx,dword ptr [esp+14h] | 51 | \\ sbb edx,0 |
| 52 | \\ L5a: | 52 | \\ L2a: |
| 53 | \\ sub eax,dword ptr [esp+8] | 53 | \\ pop ebx |
| 54 | \\ sbb edx,dword ptr [esp+0Ch] | 54 | \\ ret 10h |
| 55 | \\ neg edx | 55 | ); |
| 56 | \\ neg eax | ||
| 57 | \\ sbb edx,0 | ||
| 58 | \\ L2a: | ||
| 59 | \\ pop ebx | ||
| 60 | \\ ret 10h | ||
| 61 | ); | ||
| 62 | unreachable; | ||
| 63 | } | ||
| 64 | |||
| 65 | @setGlobalLinkage(_aullrem, builtin.GlobalLinkage.Internal); | ||
| 66 | unreachable; | ||
| 67 | } | 56 | } |
std/special/compiler_rt/comparetf2.zig+21-64| ... | @@ -20,11 +20,9 @@ const infRep = exponentMask; | ... | @@ -20,11 +20,9 @@ const infRep = exponentMask; |
| 20 | 20 | ||
| 21 | const builtin = @import("builtin"); | 21 | const builtin = @import("builtin"); |
| 22 | const is_test = builtin.is_test; | 22 | const is_test = builtin.is_test; |
| 23 | const linkage = @import("index.zig").linkage; | ||
| 24 | 23 | ||
| 25 | export fn __letf2(a: f128, b: f128) -> c_int { | 24 | pub extern fn __letf2(a: f128, b: f128) -> c_int { |
| 26 | @setDebugSafety(this, is_test); | 25 | @setDebugSafety(this, is_test); |
| 27 | @setGlobalLinkage(__letf2, linkage); | ||
| 28 | 26 | ||
| 29 | const aInt = @bitCast(rep_t, a); | 27 | const aInt = @bitCast(rep_t, a); |
| 30 | const bInt = @bitCast(rep_t, b); | 28 | const bInt = @bitCast(rep_t, b); |
| ... | @@ -40,35 +38,25 @@ export fn __letf2(a: f128, b: f128) -> c_int { | ... | @@ -40,35 +38,25 @@ export fn __letf2(a: f128, b: f128) -> c_int { |
| 40 | 38 | ||
| 41 | // If at least one of a and b is positive, we get the same result comparing | 39 | // If at least one of a and b is positive, we get the same result comparing |
| 42 | // a and b as signed integers as we would with a floating-point compare. | 40 | // a and b as signed integers as we would with a floating-point compare. |
| 43 | return if ((aInt & bInt) >= 0) { | 41 | return if ((aInt & bInt) >= 0) |
| 44 | if (aInt < bInt) { | 42 | if (aInt < bInt) |
| 45 | LE_LESS | 43 | LE_LESS |
| 46 | } else if (aInt == bInt) { | 44 | else if (aInt == bInt) |
| 47 | LE_EQUAL | 45 | LE_EQUAL |
| 48 | } else { | 46 | else |
| 49 | LE_GREATER | 47 | LE_GREATER |
| 50 | } | 48 | else |
| 51 | } else { | ||
| 52 | // Otherwise, both are negative, so we need to flip the sense of the | 49 | // Otherwise, both are negative, so we need to flip the sense of the |
| 53 | // comparison to get the correct result. (This assumes a twos- or ones- | 50 | // comparison to get the correct result. (This assumes a twos- or ones- |
| 54 | // complement integer representation; if integers are represented in a | 51 | // complement integer representation; if integers are represented in a |
| 55 | // sign-magnitude representation, then this flip is incorrect). | 52 | // sign-magnitude representation, then this flip is incorrect). |
| 56 | if (aInt > bInt) { | 53 | if (aInt > bInt) |
| 57 | LE_LESS | 54 | LE_LESS |
| 58 | } else if (aInt == bInt) { | 55 | else if (aInt == bInt) |
| 59 | LE_EQUAL | 56 | LE_EQUAL |
| 60 | } else { | 57 | else |
| 61 | LE_GREATER | 58 | LE_GREATER |
| 62 | } | 59 | ; |
| 63 | }; | ||
| 64 | } | ||
| 65 | |||
| 66 | // Alias for libgcc compatibility | ||
| 67 | // TODO https://github.com/zig-lang/zig/issues/420 | ||
| 68 | export fn __cmptf2(a: f128, b: f128) -> c_int { | ||
| 69 | @setGlobalLinkage(__cmptf2, linkage); | ||
| 70 | @setDebugSafety(this, is_test); | ||
| 71 | return __letf2(a, b); | ||
| 72 | } | 60 | } |
| 73 | 61 | ||
| 74 | // TODO https://github.com/zig-lang/zig/issues/305 | 62 | // TODO https://github.com/zig-lang/zig/issues/305 |
| ... | @@ -78,8 +66,7 @@ const GE_EQUAL = c_int(0); | ... | @@ -78,8 +66,7 @@ const GE_EQUAL = c_int(0); |
| 78 | const GE_GREATER = c_int(1); | 66 | const GE_GREATER = c_int(1); |
| 79 | const GE_UNORDERED = c_int(-1); // Note: different from LE_UNORDERED | 67 | const GE_UNORDERED = c_int(-1); // Note: different from LE_UNORDERED |
| 80 | 68 | ||
| 81 | export fn __getf2(a: f128, b: f128) -> c_int { | 69 | pub extern fn __getf2(a: f128, b: f128) -> c_int { |
| 82 | @setGlobalLinkage(__getf2, linkage); | ||
| 83 | @setDebugSafety(this, is_test); | 70 | @setDebugSafety(this, is_test); |
| 84 | 71 | ||
| 85 | const aInt = @bitCast(srep_t, a); | 72 | const aInt = @bitCast(srep_t, a); |
| ... | @@ -89,57 +76,27 @@ export fn __getf2(a: f128, b: f128) -> c_int { | ... | @@ -89,57 +76,27 @@ export fn __getf2(a: f128, b: f128) -> c_int { |
| 89 | 76 | ||
| 90 | if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED; | 77 | if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED; |
| 91 | if ((aAbs | bAbs) == 0) return GE_EQUAL; | 78 | if ((aAbs | bAbs) == 0) return GE_EQUAL; |
| 92 | return if ((aInt & bInt) >= 0) { | 79 | return if ((aInt & bInt) >= 0) |
| 93 | if (aInt < bInt) { | 80 | if (aInt < bInt) |
| 94 | GE_LESS | 81 | GE_LESS |
| 95 | } else if (aInt == bInt) { | 82 | else if (aInt == bInt) |
| 96 | GE_EQUAL | 83 | GE_EQUAL |
| 97 | } else { | 84 | else |
| 98 | GE_GREATER | 85 | GE_GREATER |
| 99 | } | 86 | else |
| 100 | } else { | 87 | if (aInt > bInt) |
| 101 | if (aInt > bInt) { | ||
| 102 | GE_LESS | 88 | GE_LESS |
| 103 | } else if (aInt == bInt) { | 89 | else if (aInt == bInt) |
| 104 | GE_EQUAL | 90 | GE_EQUAL |
| 105 | } else { | 91 | else |
| 106 | GE_GREATER | 92 | GE_GREATER |
| 107 | } | 93 | ; |
| 108 | }; | ||
| 109 | } | 94 | } |
| 110 | 95 | ||
| 111 | export fn __unordtf2(a: f128, b: f128) -> c_int { | 96 | pub extern fn __unordtf2(a: f128, b: f128) -> c_int { |
| 112 | @setGlobalLinkage(__unordtf2, linkage); | ||
| 113 | @setDebugSafety(this, is_test); | 97 | @setDebugSafety(this, is_test); |
| 114 | 98 | ||
| 115 | const aAbs = @bitCast(rep_t, a) & absMask; | 99 | const aAbs = @bitCast(rep_t, a) & absMask; |
| 116 | const bAbs = @bitCast(rep_t, b) & absMask; | 100 | const bAbs = @bitCast(rep_t, b) & absMask; |
| 117 | return c_int(aAbs > infRep or bAbs > infRep); | 101 | return c_int(aAbs > infRep or bAbs > infRep); |
| 118 | } | 102 | } |
| 119 | |||
| 120 | // The following are alternative names for the preceding routines. | ||
| 121 | // TODO use aliases https://github.com/zig-lang/zig/issues/462 | ||
| 122 | |||
| 123 | export fn __eqtf2(a: f128, b: f128) -> c_int { | ||
| 124 | @setGlobalLinkage(__eqtf2, linkage); | ||
| 125 | @setDebugSafety(this, is_test); | ||
| 126 | return __letf2(a, b); | ||
| 127 | } | ||
| 128 | |||
| 129 | export fn __lttf2(a: f128, b: f128) -> c_int { | ||
| 130 | @setGlobalLinkage(__lttf2, linkage); | ||
| 131 | @setDebugSafety(this, is_test); | ||
| 132 | return __letf2(a, b); | ||
| 133 | } | ||
| 134 | |||
| 135 | export fn __netf2(a: f128, b: f128) -> c_int { | ||
| 136 | @setGlobalLinkage(__netf2, linkage); | ||
| 137 | @setDebugSafety(this, is_test); | ||
| 138 | return __letf2(a, b); | ||
| 139 | } | ||
| 140 | |||
| 141 | export fn __gttf2(a: f128, b: f128) -> c_int { | ||
| 142 | @setGlobalLinkage(__gttf2, linkage); | ||
| 143 | @setDebugSafety(this, is_test); | ||
| 144 | return __getf2(a, b); | ||
| 145 | } |
std/special/compiler_rt/fixunsdfdi.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const fixuint = @import("fixuint.zig").fixuint; | 1 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __fixunsdfdi(a: f64) -> u64 { | 4 | pub extern fn __fixunsdfdi(a: f64) -> u64 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__fixunsdfdi, linkage); | ||
| 8 | return fixuint(f64, u64, a); | 6 | return fixuint(f64, u64, a); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/fixunsdfsi.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const fixuint = @import("fixuint.zig").fixuint; | 1 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __fixunsdfsi(a: f64) -> u32 { | 4 | pub extern fn __fixunsdfsi(a: f64) -> u32 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__fixunsdfsi, linkage); | ||
| 8 | return fixuint(f64, u32, a); | 6 | return fixuint(f64, u32, a); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/fixunsdfti.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const fixuint = @import("fixuint.zig").fixuint; | 1 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __fixunsdfti(a: f64) -> u128 { | 4 | pub extern fn __fixunsdfti(a: f64) -> u128 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__fixunsdfti, linkage); | ||
| 8 | return fixuint(f64, u128, a); | 6 | return fixuint(f64, u128, a); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/fixunssfdi.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const fixuint = @import("fixuint.zig").fixuint; | 1 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __fixunssfdi(a: f32) -> u64 { | 4 | pub extern fn __fixunssfdi(a: f32) -> u64 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__fixunssfdi, linkage); | ||
| 8 | return fixuint(f32, u64, a); | 6 | return fixuint(f32, u64, a); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/fixunssfsi.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const fixuint = @import("fixuint.zig").fixuint; | 1 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __fixunssfsi(a: f32) -> u32 { | 4 | pub extern fn __fixunssfsi(a: f32) -> u32 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__fixunssfsi, linkage); | ||
| 8 | return fixuint(f32, u32, a); | 6 | return fixuint(f32, u32, a); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/fixunssfti.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const fixuint = @import("fixuint.zig").fixuint; | 1 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __fixunssfti(a: f32) -> u128 { | 4 | pub extern fn __fixunssfti(a: f32) -> u128 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__fixunssfti, linkage); | ||
| 8 | return fixuint(f32, u128, a); | 6 | return fixuint(f32, u128, a); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/fixunstfdi.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const fixuint = @import("fixuint.zig").fixuint; | 1 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __fixunstfdi(a: f128) -> u64 { | 4 | pub extern fn __fixunstfdi(a: f128) -> u64 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__fixunstfdi, linkage); | ||
| 8 | return fixuint(f128, u64, a); | 6 | return fixuint(f128, u64, a); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/fixunstfsi.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const fixuint = @import("fixuint.zig").fixuint; | 1 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __fixunstfsi(a: f128) -> u32 { | 4 | pub extern fn __fixunstfsi(a: f128) -> u32 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__fixunstfsi, linkage); | ||
| 8 | return fixuint(f128, u32, a); | 6 | return fixuint(f128, u32, a); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/fixunstfti.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const fixuint = @import("fixuint.zig").fixuint; | 1 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __fixunstfti(a: f128) -> u128 { | 4 | pub extern fn __fixunstfti(a: f128) -> u128 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__fixunstfti, linkage); | ||
| 8 | return fixuint(f128, u128, a); | 6 | return fixuint(f128, u128, a); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/index.zig+165-176| ... | @@ -1,33 +1,74 @@ | ... | @@ -1,33 +1,74 @@ |
| 1 | comptime { | ||
| 2 | _ = @import("comparetf2.zig"); | ||
| 3 | _ = @import("fixunsdfdi.zig"); | ||
| 4 | _ = @import("fixunsdfsi.zig"); | ||
| 5 | _ = @import("fixunsdfti.zig"); | ||
| 6 | _ = @import("fixunssfdi.zig"); | ||
| 7 | _ = @import("fixunssfsi.zig"); | ||
| 8 | _ = @import("fixunssfti.zig"); | ||
| 9 | _ = @import("fixunstfdi.zig"); | ||
| 10 | _ = @import("fixunstfsi.zig"); | ||
| 11 | _ = @import("fixunstfti.zig"); | ||
| 12 | _ = @import("udivmoddi4.zig"); | ||
| 13 | _ = @import("udivmodti4.zig"); | ||
| 14 | _ = @import("udivti3.zig"); | ||
| 15 | _ = @import("umodti3.zig"); | ||
| 16 | _ = @import("aulldiv.zig"); | ||
| 17 | _ = @import("aullrem.zig"); | ||
| 18 | } | ||
| 19 | |||
| 20 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 21 | const is_test = builtin.is_test; | 2 | const is_test = builtin.is_test; |
| 22 | const assert = @import("../../debug.zig").assert; | ||
| 23 | 3 | ||
| 4 | comptime { | ||
| 5 | const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; | ||
| 6 | const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; | ||
| 7 | |||
| 8 | @export("__letf2", @import("comparetf2.zig").__letf2, linkage); | ||
| 9 | @export("__getf2", @import("comparetf2.zig").__getf2, linkage); | ||
| 10 | |||
| 11 | if (!is_test) { | ||
| 12 | // only create these aliases when not testing | ||
| 13 | @export("__cmptf2", @import("comparetf2.zig").__letf2, linkage); | ||
| 14 | @export("__eqtf2", @import("comparetf2.zig").__letf2, linkage); | ||
| 15 | @export("__lttf2", @import("comparetf2.zig").__letf2, linkage); | ||
| 16 | @export("__netf2", @import("comparetf2.zig").__letf2, linkage); | ||
| 17 | @export("__gttf2", @import("comparetf2.zig").__getf2, linkage); | ||
| 18 | } | ||
| 19 | |||
| 20 | @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage); | ||
| 21 | |||
| 22 | @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage); | ||
| 23 | @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage); | ||
| 24 | @export("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage); | ||
| 25 | |||
| 26 | @export("__fixunsdfsi", @import("fixunsdfsi.zig").__fixunsdfsi, linkage); | ||
| 27 | @export("__fixunsdfdi", @import("fixunsdfdi.zig").__fixunsdfdi, linkage); | ||
| 28 | @export("__fixunsdfti", @import("fixunsdfti.zig").__fixunsdfti, linkage); | ||
| 29 | |||
| 30 | @export("__fixunstfsi", @import("fixunstfsi.zig").__fixunstfsi, linkage); | ||
| 31 | @export("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage); | ||
| 32 | @export("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage); | ||
| 33 | |||
| 34 | @export("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage); | ||
| 35 | @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage); | ||
| 24 | 36 | ||
| 25 | const win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; | 37 | @export("__udivti3", @import("udivti3.zig").__udivti3, linkage); |
| 26 | const win64 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.x86_64; | 38 | @export("__umodti3", @import("umodti3.zig").__umodti3, linkage); |
| 27 | const win32_nocrt = win32 and !builtin.link_libc; | 39 | |
| 28 | const win64_nocrt = win64 and !builtin.link_libc; | 40 | @export("__udivsi3", __udivsi3, linkage); |
| 29 | pub const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; | 41 | @export("__udivdi3", __udivdi3, linkage); |
| 30 | const strong_linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; | 42 | @export("__umoddi3", __umoddi3, linkage); |
| 43 | @export("__udivmodsi4", __udivmodsi4, linkage); | ||
| 44 | |||
| 45 | if (isArmArch()) { | ||
| 46 | @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage); | ||
| 47 | @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage); | ||
| 48 | @export("__aeabi_uidiv", __udivsi3, linkage); | ||
| 49 | } | ||
| 50 | if (builtin.os == builtin.Os.windows) { | ||
| 51 | switch (builtin.arch) { | ||
| 52 | builtin.Arch.i386 => { | ||
| 53 | if (!builtin.link_libc) { | ||
| 54 | @export("_chkstk", _chkstk, strong_linkage); | ||
| 55 | @export("__chkstk_ms", __chkstk_ms, linkage); | ||
| 56 | } | ||
| 57 | @export("_aulldiv", @import("aulldiv.zig")._aulldiv, strong_linkage); | ||
| 58 | @export("_aullrem", @import("aullrem.zig")._aullrem, strong_linkage); | ||
| 59 | }, | ||
| 60 | builtin.Arch.x86_64 => { | ||
| 61 | if (!builtin.link_libc) { | ||
| 62 | @export("__chkstk", __chkstk, strong_linkage); | ||
| 63 | @export("___chkstk_ms", ___chkstk_ms, linkage); | ||
| 64 | } | ||
| 65 | }, | ||
| 66 | else => {}, | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | const assert = @import("../../debug.zig").assert; | ||
| 31 | 72 | ||
| 32 | const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; | 73 | const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; |
| 33 | 74 | ||
| ... | @@ -41,15 +82,13 @@ pub coldcc fn panic(msg: []const u8) -> noreturn { | ... | @@ -41,15 +82,13 @@ pub coldcc fn panic(msg: []const u8) -> noreturn { |
| 41 | } | 82 | } |
| 42 | } | 83 | } |
| 43 | 84 | ||
| 44 | export fn __udivdi3(a: u64, b: u64) -> u64 { | 85 | extern fn __udivdi3(a: u64, b: u64) -> u64 { |
| 45 | @setDebugSafety(this, is_test); | 86 | @setDebugSafety(this, is_test); |
| 46 | @setGlobalLinkage(__udivdi3, linkage); | ||
| 47 | return __udivmoddi4(a, b, null); | 87 | return __udivmoddi4(a, b, null); |
| 48 | } | 88 | } |
| 49 | 89 | ||
| 50 | export fn __umoddi3(a: u64, b: u64) -> u64 { | 90 | extern fn __umoddi3(a: u64, b: u64) -> u64 { |
| 51 | @setDebugSafety(this, is_test); | 91 | @setDebugSafety(this, is_test); |
| 52 | @setGlobalLinkage(__umoddi3, linkage); | ||
| 53 | 92 | ||
| 54 | var r: u64 = undefined; | 93 | var r: u64 = undefined; |
| 55 | _ = __udivmoddi4(a, b, &r); | 94 | _ = __udivmoddi4(a, b, &r); |
| ... | @@ -60,17 +99,11 @@ const AeabiUlDivModResult = extern struct { | ... | @@ -60,17 +99,11 @@ const AeabiUlDivModResult = extern struct { |
| 60 | quot: u64, | 99 | quot: u64, |
| 61 | rem: u64, | 100 | rem: u64, |
| 62 | }; | 101 | }; |
| 63 | export fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult { | 102 | extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult { |
| 64 | @setDebugSafety(this, is_test); | 103 | @setDebugSafety(this, is_test); |
| 65 | if (comptime isArmArch()) { | 104 | var result: AeabiUlDivModResult = undefined; |
| 66 | @setGlobalLinkage(__aeabi_uldivmod, linkage); | 105 | result.quot = __udivmoddi4(numerator, denominator, &result.rem); |
| 67 | var result: AeabiUlDivModResult = undefined; | 106 | return result; |
| 68 | result.quot = __udivmoddi4(numerator, denominator, &result.rem); | ||
| 69 | return result; | ||
| 70 | } | ||
| 71 | |||
| 72 | @setGlobalLinkage(__aeabi_uldivmod, builtin.GlobalLinkage.Internal); | ||
| 73 | unreachable; | ||
| 74 | } | 107 | } |
| 75 | 108 | ||
| 76 | fn isArmArch() -> bool { | 109 | fn isArmArch() -> bool { |
| ... | @@ -115,156 +148,124 @@ fn isArmArch() -> bool { | ... | @@ -115,156 +148,124 @@ fn isArmArch() -> bool { |
| 115 | }; | 148 | }; |
| 116 | } | 149 | } |
| 117 | 150 | ||
| 118 | export nakedcc fn __aeabi_uidivmod() { | 151 | nakedcc fn __aeabi_uidivmod() { |
| 119 | @setDebugSafety(this, false); | 152 | @setDebugSafety(this, false); |
| 120 | 153 | asm volatile ( | |
| 121 | if (comptime isArmArch()) { | 154 | \\ push { lr } |
| 122 | @setGlobalLinkage(__aeabi_uidivmod, linkage); | 155 | \\ sub sp, sp, #4 |
| 123 | asm volatile ( | 156 | \\ mov r2, sp |
| 124 | \\ push { lr } | 157 | \\ bl __udivmodsi4 |
| 125 | \\ sub sp, sp, #4 | 158 | \\ ldr r1, [sp] |
| 126 | \\ mov r2, sp | 159 | \\ add sp, sp, #4 |
| 127 | \\ bl __udivmodsi4 | 160 | \\ pop { pc } |
| 128 | \\ ldr r1, [sp] | 161 | ::: "r2", "r1"); |
| 129 | \\ add sp, sp, #4 | ||
| 130 | \\ pop { pc } | ||
| 131 | ::: "r2", "r1"); | ||
| 132 | unreachable; | ||
| 133 | } | ||
| 134 | |||
| 135 | @setGlobalLinkage(__aeabi_uidivmod, builtin.GlobalLinkage.Internal); | ||
| 136 | } | 162 | } |
| 137 | 163 | ||
| 138 | // _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments, | 164 | // _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments, |
| 139 | // then decrement %esp by %eax. Preserves all registers except %esp and flags. | 165 | // then decrement %esp by %eax. Preserves all registers except %esp and flags. |
| 140 | // This routine is windows specific | 166 | // This routine is windows specific |
| 141 | // http://msdn.microsoft.com/en-us/library/ms648426.aspx | 167 | // http://msdn.microsoft.com/en-us/library/ms648426.aspx |
| 142 | export nakedcc fn _chkstk() align(4) { | 168 | nakedcc fn _chkstk() align(4) { |
| 143 | @setDebugSafety(this, false); | 169 | @setDebugSafety(this, false); |
| 144 | 170 | ||
| 145 | if (win32_nocrt) { | 171 | asm volatile ( |
| 146 | @setGlobalLinkage(_chkstk, strong_linkage); | 172 | \\ push %%ecx |
| 147 | asm volatile ( | 173 | \\ push %%eax |
| 148 | \\ push %%ecx | 174 | \\ cmp $0x1000,%%eax |
| 149 | \\ push %%eax | 175 | \\ lea 12(%%esp),%%ecx |
| 150 | \\ cmp $0x1000,%%eax | 176 | \\ jb 1f |
| 151 | \\ lea 12(%%esp),%%ecx | 177 | \\ 2: |
| 152 | \\ jb 1f | 178 | \\ sub $0x1000,%%ecx |
| 153 | \\ 2: | 179 | \\ test %%ecx,(%%ecx) |
| 154 | \\ sub $0x1000,%%ecx | 180 | \\ sub $0x1000,%%eax |
| 155 | \\ test %%ecx,(%%ecx) | 181 | \\ cmp $0x1000,%%eax |
| 156 | \\ sub $0x1000,%%eax | 182 | \\ ja 2b |
| 157 | \\ cmp $0x1000,%%eax | 183 | \\ 1: |
| 158 | \\ ja 2b | 184 | \\ sub %%eax,%%ecx |
| 159 | \\ 1: | 185 | \\ test %%ecx,(%%ecx) |
| 160 | \\ sub %%eax,%%ecx | 186 | \\ pop %%eax |
| 161 | \\ test %%ecx,(%%ecx) | 187 | \\ pop %%ecx |
| 162 | \\ pop %%eax | 188 | \\ ret |
| 163 | \\ pop %%ecx | 189 | ); |
| 164 | \\ ret | ||
| 165 | ); | ||
| 166 | unreachable; | ||
| 167 | } | ||
| 168 | |||
| 169 | @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal); | ||
| 170 | } | 190 | } |
| 171 | 191 | ||
| 172 | export nakedcc fn __chkstk() align(4) { | 192 | nakedcc fn __chkstk() align(4) { |
| 173 | @setDebugSafety(this, false); | 193 | @setDebugSafety(this, false); |
| 174 | 194 | ||
| 175 | if (win64_nocrt) { | 195 | asm volatile ( |
| 176 | @setGlobalLinkage(__chkstk, strong_linkage); | 196 | \\ push %%rcx |
| 177 | asm volatile ( | 197 | \\ push %%rax |
| 178 | \\ push %%rcx | 198 | \\ cmp $0x1000,%%rax |
| 179 | \\ push %%rax | 199 | \\ lea 24(%%rsp),%%rcx |
| 180 | \\ cmp $0x1000,%%rax | 200 | \\ jb 1f |
| 181 | \\ lea 24(%%rsp),%%rcx | 201 | \\2: |
| 182 | \\ jb 1f | 202 | \\ sub $0x1000,%%rcx |
| 183 | \\2: | 203 | \\ test %%rcx,(%%rcx) |
| 184 | \\ sub $0x1000,%%rcx | 204 | \\ sub $0x1000,%%rax |
| 185 | \\ test %%rcx,(%%rcx) | 205 | \\ cmp $0x1000,%%rax |
| 186 | \\ sub $0x1000,%%rax | 206 | \\ ja 2b |
| 187 | \\ cmp $0x1000,%%rax | 207 | \\1: |
| 188 | \\ ja 2b | 208 | \\ sub %%rax,%%rcx |
| 189 | \\1: | 209 | \\ test %%rcx,(%%rcx) |
| 190 | \\ sub %%rax,%%rcx | 210 | \\ pop %%rax |
| 191 | \\ test %%rcx,(%%rcx) | 211 | \\ pop %%rcx |
| 192 | \\ pop %%rax | 212 | \\ ret |
| 193 | \\ pop %%rcx | 213 | ); |
| 194 | \\ ret | ||
| 195 | ); | ||
| 196 | unreachable; | ||
| 197 | } | ||
| 198 | |||
| 199 | @setGlobalLinkage(__chkstk, builtin.GlobalLinkage.Internal); | ||
| 200 | } | 214 | } |
| 201 | 215 | ||
| 202 | // _chkstk routine | 216 | // _chkstk routine |
| 203 | // This routine is windows specific | 217 | // This routine is windows specific |
| 204 | // http://msdn.microsoft.com/en-us/library/ms648426.aspx | 218 | // http://msdn.microsoft.com/en-us/library/ms648426.aspx |
| 205 | export nakedcc fn __chkstk_ms() align(4) { | 219 | nakedcc fn __chkstk_ms() align(4) { |
| 206 | @setDebugSafety(this, false); | 220 | @setDebugSafety(this, false); |
| 207 | 221 | ||
| 208 | if (win32_nocrt) { | 222 | asm volatile ( |
| 209 | @setGlobalLinkage(__chkstk_ms, linkage); | 223 | \\ push %%ecx |
| 210 | asm volatile ( | 224 | \\ push %%eax |
| 211 | \\ push %%ecx | 225 | \\ cmp $0x1000,%%eax |
| 212 | \\ push %%eax | 226 | \\ lea 12(%%esp),%%ecx |
| 213 | \\ cmp $0x1000,%%eax | 227 | \\ jb 1f |
| 214 | \\ lea 12(%%esp),%%ecx | 228 | \\ 2: |
| 215 | \\ jb 1f | 229 | \\ sub $0x1000,%%ecx |
| 216 | \\ 2: | 230 | \\ test %%ecx,(%%ecx) |
| 217 | \\ sub $0x1000,%%ecx | 231 | \\ sub $0x1000,%%eax |
| 218 | \\ test %%ecx,(%%ecx) | 232 | \\ cmp $0x1000,%%eax |
| 219 | \\ sub $0x1000,%%eax | 233 | \\ ja 2b |
| 220 | \\ cmp $0x1000,%%eax | 234 | \\ 1: |
| 221 | \\ ja 2b | 235 | \\ sub %%eax,%%ecx |
| 222 | \\ 1: | 236 | \\ test %%ecx,(%%ecx) |
| 223 | \\ sub %%eax,%%ecx | 237 | \\ pop %%eax |
| 224 | \\ test %%ecx,(%%ecx) | 238 | \\ pop %%ecx |
| 225 | \\ pop %%eax | 239 | \\ ret |
| 226 | \\ pop %%ecx | 240 | ); |
| 227 | \\ ret | ||
| 228 | ); | ||
| 229 | unreachable; | ||
| 230 | } | ||
| 231 | |||
| 232 | @setGlobalLinkage(__chkstk_ms, builtin.GlobalLinkage.Internal); | ||
| 233 | } | 241 | } |
| 234 | 242 | ||
| 235 | export nakedcc fn ___chkstk_ms() align(4) { | 243 | nakedcc fn ___chkstk_ms() align(4) { |
| 236 | @setDebugSafety(this, false); | 244 | @setDebugSafety(this, false); |
| 237 | 245 | ||
| 238 | if (win64_nocrt) { | 246 | asm volatile ( |
| 239 | @setGlobalLinkage(___chkstk_ms, linkage); | 247 | \\ push %%rcx |
| 240 | asm volatile ( | 248 | \\ push %%rax |
| 241 | \\ push %%rcx | 249 | \\ cmp $0x1000,%%rax |
| 242 | \\ push %%rax | 250 | \\ lea 24(%%rsp),%%rcx |
| 243 | \\ cmp $0x1000,%%rax | 251 | \\ jb 1f |
| 244 | \\ lea 24(%%rsp),%%rcx | 252 | \\2: |
| 245 | \\ jb 1f | 253 | \\ sub $0x1000,%%rcx |
| 246 | \\2: | 254 | \\ test %%rcx,(%%rcx) |
| 247 | \\ sub $0x1000,%%rcx | 255 | \\ sub $0x1000,%%rax |
| 248 | \\ test %%rcx,(%%rcx) | 256 | \\ cmp $0x1000,%%rax |
| 249 | \\ sub $0x1000,%%rax | 257 | \\ ja 2b |
| 250 | \\ cmp $0x1000,%%rax | 258 | \\1: |
| 251 | \\ ja 2b | 259 | \\ sub %%rax,%%rcx |
| 252 | \\1: | 260 | \\ test %%rcx,(%%rcx) |
| 253 | \\ sub %%rax,%%rcx | 261 | \\ pop %%rax |
| 254 | \\ test %%rcx,(%%rcx) | 262 | \\ pop %%rcx |
| 255 | \\ pop %%rax | 263 | \\ ret |
| 256 | \\ pop %%rcx | 264 | ); |
| 257 | \\ ret | ||
| 258 | ); | ||
| 259 | unreachable; | ||
| 260 | } | ||
| 261 | |||
| 262 | @setGlobalLinkage(___chkstk_ms, builtin.GlobalLinkage.Internal); | ||
| 263 | } | 265 | } |
| 264 | 266 | ||
| 265 | export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { | 267 | extern fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { |
| 266 | @setDebugSafety(this, is_test); | 268 | @setDebugSafety(this, is_test); |
| 267 | @setGlobalLinkage(__udivmodsi4, linkage); | ||
| 268 | 269 | ||
| 269 | const d = __udivsi3(a, b); | 270 | const d = __udivsi3(a, b); |
| 270 | *rem = u32(i32(a) -% (i32(d) * i32(b))); | 271 | *rem = u32(i32(a) -% (i32(d) * i32(b))); |
| ... | @@ -272,19 +273,8 @@ export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { | ... | @@ -272,19 +273,8 @@ export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { |
| 272 | } | 273 | } |
| 273 | 274 | ||
| 274 | 275 | ||
| 275 | // TODO make this an alias instead of an extra function call | 276 | extern fn __udivsi3(n: u32, d: u32) -> u32 { |
| 276 | // https://github.com/andrewrk/zig/issues/256 | ||
| 277 | |||
| 278 | export fn __aeabi_uidiv(n: u32, d: u32) -> u32 { | ||
| 279 | @setDebugSafety(this, is_test); | 277 | @setDebugSafety(this, is_test); |
| 280 | @setGlobalLinkage(__aeabi_uidiv, linkage); | ||
| 281 | |||
| 282 | return __udivsi3(n, d); | ||
| 283 | } | ||
| 284 | |||
| 285 | export fn __udivsi3(n: u32, d: u32) -> u32 { | ||
| 286 | @setDebugSafety(this, is_test); | ||
| 287 | @setGlobalLinkage(__udivsi3, linkage); | ||
| 288 | 278 | ||
| 289 | const n_uword_bits: c_uint = u32.bit_count; | 279 | const n_uword_bits: c_uint = u32.bit_count; |
| 290 | // special cases | 280 | // special cases |
| ... | @@ -480,4 +470,3 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) { | ... | @@ -480,4 +470,3 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) { |
| 480 | const q: u32 = __udivsi3(a, b); | 470 | const q: u32 = __udivsi3(a, b); |
| 481 | assert(q == expected_q); | 471 | assert(q == expected_q); |
| 482 | } | 472 | } |
| 483 |
std/special/compiler_rt/udivmoddi4.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const udivmod = @import("udivmod.zig").udivmod; | 1 | const udivmod = @import("udivmod.zig").udivmod; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) -> u64 { | 4 | pub extern fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) -> u64 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__udivmoddi4, linkage); | ||
| 8 | return udivmod(u64, a, b, maybe_rem); | 6 | return udivmod(u64, a, b, maybe_rem); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/udivmodti4.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const udivmod = @import("udivmod.zig").udivmod; | 1 | const udivmod = @import("udivmod.zig").udivmod; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) -> u128 { | 4 | pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) -> u128 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__udivmodti4, linkage); | ||
| 8 | return udivmod(u128, a, b, maybe_rem); | 6 | return udivmod(u128, a, b, maybe_rem); |
| 9 | } | 7 | } |
| 10 | 8 |
std/special/compiler_rt/udivti3.zig+1-3| ... | @@ -1,9 +1,7 @@ | ... | @@ -1,9 +1,7 @@ |
| 1 | const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; | 1 | const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __udivti3(a: u128, b: u128) -> u128 { | 4 | pub extern fn __udivti3(a: u128, b: u128) -> u128 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__udivti3, linkage); | ||
| 8 | return __udivmodti4(a, b, null); | 6 | return __udivmodti4(a, b, null); |
| 9 | } | 7 | } |
std/special/compiler_rt/umodti3.zig+1-3| ... | @@ -1,10 +1,8 @@ | ... | @@ -1,10 +1,8 @@ |
| 1 | const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; | 1 | const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const linkage = @import("index.zig").linkage; | ||
| 4 | 3 | ||
| 5 | export fn __umodti3(a: u128, b: u128) -> u128 { | 4 | pub extern fn __umodti3(a: u128, b: u128) -> u128 { |
| 6 | @setDebugSafety(this, builtin.is_test); | 5 | @setDebugSafety(this, builtin.is_test); |
| 7 | @setGlobalLinkage(__umodti3, linkage); | ||
| 8 | var r: u128 = undefined; | 6 | var r: u128 = undefined; |
| 9 | _ = __udivmodti4(a, b, &r); | 7 | _ = __udivmodti4(a, b, &r); |
| 10 | return r; | 8 | return r; |
test/behavior.zig+2-1| ... | @@ -7,6 +7,8 @@ comptime { | ... | @@ -7,6 +7,8 @@ comptime { |
| 7 | _ = @import("cases/bitcast.zig"); | 7 | _ = @import("cases/bitcast.zig"); |
| 8 | _ = @import("cases/bool.zig"); | 8 | _ = @import("cases/bool.zig"); |
| 9 | _ = @import("cases/bugs/394.zig"); | 9 | _ = @import("cases/bugs/394.zig"); |
| 10 | _ = @import("cases/bugs/655.zig"); | ||
| 11 | _ = @import("cases/bugs/656.zig"); | ||
| 10 | _ = @import("cases/cast.zig"); | 12 | _ = @import("cases/cast.zig"); |
| 11 | _ = @import("cases/const_slice_child.zig"); | 13 | _ = @import("cases/const_slice_child.zig"); |
| 12 | _ = @import("cases/defer.zig"); | 14 | _ = @import("cases/defer.zig"); |
| ... | @@ -18,7 +20,6 @@ comptime { | ... | @@ -18,7 +20,6 @@ comptime { |
| 18 | _ = @import("cases/fn.zig"); | 20 | _ = @import("cases/fn.zig"); |
| 19 | _ = @import("cases/for.zig"); | 21 | _ = @import("cases/for.zig"); |
| 20 | _ = @import("cases/generics.zig"); | 22 | _ = @import("cases/generics.zig"); |
| 21 | _ = @import("cases/goto.zig"); | ||
| 22 | _ = @import("cases/if.zig"); | 23 | _ = @import("cases/if.zig"); |
| 23 | _ = @import("cases/import.zig"); | 24 | _ = @import("cases/import.zig"); |
| 24 | _ = @import("cases/incomplete_struct_param_tld.zig"); | 25 | _ = @import("cases/incomplete_struct_param_tld.zig"); |
test/cases/align.zig+9-9| ... | @@ -10,7 +10,7 @@ test "global variable alignment" { | ... | @@ -10,7 +10,7 @@ test "global variable alignment" { |
| 10 | assert(@typeOf(slice) == []align(4) u8); | 10 | assert(@typeOf(slice) == []align(4) u8); |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | fn derp() align(@sizeOf(usize) * 2) -> i32 { 1234 } | 13 | fn derp() align(@sizeOf(usize) * 2) -> i32 { return 1234; } |
| 14 | fn noop1() align(1) {} | 14 | fn noop1() align(1) {} |
| 15 | fn noop4() align(4) {} | 15 | fn noop4() align(4) {} |
| 16 | 16 | ||
| ... | @@ -53,14 +53,14 @@ test "implicitly decreasing pointer alignment" { | ... | @@ -53,14 +53,14 @@ test "implicitly decreasing pointer alignment" { |
| 53 | assert(addUnaligned(&a, &b) == 7); | 53 | assert(addUnaligned(&a, &b) == 7); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) -> u32 { *a + *b } | 56 | fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) -> u32 { return *a + *b; } |
| 57 | 57 | ||
| 58 | test "implicitly decreasing slice alignment" { | 58 | test "implicitly decreasing slice alignment" { |
| 59 | const a: u32 align(4) = 3; | 59 | const a: u32 align(4) = 3; |
| 60 | const b: u32 align(8) = 4; | 60 | const b: u32 align(8) = 4; |
| 61 | assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7); | 61 | assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7); |
| 62 | } | 62 | } |
| 63 | fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) -> u32 { a[0] + b[0] } | 63 | fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) -> u32 { return a[0] + b[0]; } |
| 64 | 64 | ||
| 65 | test "specifying alignment allows pointer cast" { | 65 | test "specifying alignment allows pointer cast" { |
| 66 | testBytesAlign(0x33); | 66 | testBytesAlign(0x33); |
| ... | @@ -115,20 +115,20 @@ fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) -> i32, answer: i32) { | ... | @@ -115,20 +115,20 @@ fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) -> i32, answer: i32) { |
| 115 | assert(ptr() == answer); | 115 | assert(ptr() == answer); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | fn alignedSmall() align(8) -> i32 { 1234 } | 118 | fn alignedSmall() align(8) -> i32 { return 1234; } |
| 119 | fn alignedBig() align(16) -> i32 { 5678 } | 119 | fn alignedBig() align(16) -> i32 { return 5678; } |
| 120 | 120 | ||
| 121 | 121 | ||
| 122 | test "@alignCast functions" { | 122 | test "@alignCast functions" { |
| 123 | assert(fnExpectsOnly1(simple4) == 0x19); | 123 | assert(fnExpectsOnly1(simple4) == 0x19); |
| 124 | } | 124 | } |
| 125 | fn fnExpectsOnly1(ptr: fn()align(1) -> i32) -> i32 { | 125 | fn fnExpectsOnly1(ptr: fn()align(1) -> i32) -> i32 { |
| 126 | fnExpects4(@alignCast(4, ptr)) | 126 | return fnExpects4(@alignCast(4, ptr)); |
| 127 | } | 127 | } |
| 128 | fn fnExpects4(ptr: fn()align(4) -> i32) -> i32 { | 128 | fn fnExpects4(ptr: fn()align(4) -> i32) -> i32 { |
| 129 | ptr() | 129 | return ptr(); |
| 130 | } | 130 | } |
| 131 | fn simple4() align(4) -> i32 { 0x19 } | 131 | fn simple4() align(4) -> i32 { return 0x19; } |
| 132 | 132 | ||
| 133 | 133 | ||
| 134 | test "generic function with align param" { | 134 | test "generic function with align param" { |
| ... | @@ -137,7 +137,7 @@ test "generic function with align param" { | ... | @@ -137,7 +137,7 @@ test "generic function with align param" { |
| 137 | assert(whyWouldYouEverDoThis(8) == 0x1); | 137 | assert(whyWouldYouEverDoThis(8) == 0x1); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) -> u8 { 0x1 } | 140 | fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) -> u8 { return 0x1; } |
| 141 | 141 | ||
| 142 | 142 | ||
| 143 | test "@ptrCast preserves alignment of bigger source" { | 143 | test "@ptrCast preserves alignment of bigger source" { |
test/cases/array.zig+2-2| ... | @@ -22,7 +22,7 @@ test "arrays" { | ... | @@ -22,7 +22,7 @@ test "arrays" { |
| 22 | assert(getArrayLen(array) == 5); | 22 | assert(getArrayLen(array) == 5); |
| 23 | } | 23 | } |
| 24 | fn getArrayLen(a: []const u32) -> usize { | 24 | fn getArrayLen(a: []const u32) -> usize { |
| 25 | a.len | 25 | return a.len; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | test "void arrays" { | 28 | test "void arrays" { |
| ... | @@ -41,7 +41,7 @@ test "array literal" { | ... | @@ -41,7 +41,7 @@ test "array literal" { |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | test "array dot len const expr" { | 43 | test "array dot len const expr" { |
| 44 | assert(comptime {some_array.len == 4}); | 44 | assert(comptime x: {break :x some_array.len == 4;}); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | const ArrayDotLenConstExpr = struct { | 47 | const ArrayDotLenConstExpr = struct { |
test/cases/bitcast.zig+2-2| ... | @@ -10,5 +10,5 @@ fn testBitCast_i32_u32() { | ... | @@ -10,5 +10,5 @@ fn testBitCast_i32_u32() { |
| 10 | assert(conv2(@maxValue(u32)) == -1); | 10 | assert(conv2(@maxValue(u32)) == -1); |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | fn conv(x: i32) -> u32 { @bitCast(u32, x) } | 13 | fn conv(x: i32) -> u32 { return @bitCast(u32, x); } |
| 14 | fn conv2(x: u32) -> i32 { @bitCast(i32, x) } | 14 | fn conv2(x: u32) -> i32 { return @bitCast(i32, x); } |
test/cases/bool.zig+1-1| ... | @@ -22,7 +22,7 @@ test "bool cmp" { | ... | @@ -22,7 +22,7 @@ test "bool cmp" { |
| 22 | assert(testBoolCmp(true, false) == false); | 22 | assert(testBoolCmp(true, false) == false); |
| 23 | } | 23 | } |
| 24 | fn testBoolCmp(a: bool, b: bool) -> bool { | 24 | fn testBoolCmp(a: bool, b: bool) -> bool { |
| 25 | a == b | 25 | return a == b; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | const global_f = false; | 28 | const global_f = false; |
test/cases/bugs/655.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const other_file = @import("655_other_file.zig"); | ||
| 3 | |||
| 4 | test "function with &const parameter with type dereferenced by namespace" { | ||
| 5 | const x: other_file.Integer = 1234; | ||
| 6 | comptime std.debug.assert(@typeOf(&x) == &const other_file.Integer); | ||
| 7 | foo(x); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn foo(x: &const other_file.Integer) { | ||
| 11 | std.debug.assert(*x == 1234); | ||
| 12 | } | ||
test/cases/bugs/655_other_file.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | pub const Integer = u32; | ||
test/cases/bugs/656.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const PrefixOp = union(enum) { | ||
| 4 | Return, | ||
| 5 | AddrOf: Value, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const Value = struct { | ||
| 9 | align_expr: ?u32, | ||
| 10 | }; | ||
| 11 | |||
| 12 | test "nullable if after an if in a switch prong of a switch with 2 prongs in an else" { | ||
| 13 | foo(false, true); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn foo(a: bool, b: bool) { | ||
| 17 | var prefix_op = PrefixOp { .AddrOf = Value { .align_expr = 1234 } }; | ||
| 18 | if (a) { | ||
| 19 | } else { | ||
| 20 | switch (prefix_op) { | ||
| 21 | PrefixOp.AddrOf => |addr_of_info| { | ||
| 22 | if (b) { } | ||
| 23 | if (addr_of_info.align_expr) |align_expr| { | ||
| 24 | assert(align_expr == 1234); | ||
| 25 | } | ||
| 26 | }, | ||
| 27 | PrefixOp.Return => {}, | ||
| 28 | } | ||
| 29 | } | ||
| 30 | } | ||
test/cases/cast.zig+7-7| ... | @@ -50,7 +50,7 @@ test "peer resolve arrays of different size to const slice" { | ... | @@ -50,7 +50,7 @@ test "peer resolve arrays of different size to const slice" { |
| 50 | comptime assert(mem.eql(u8, boolToStr(false), "false")); | 50 | comptime assert(mem.eql(u8, boolToStr(false), "false")); |
| 51 | } | 51 | } |
| 52 | fn boolToStr(b: bool) -> []const u8 { | 52 | fn boolToStr(b: bool) -> []const u8 { |
| 53 | if (b) "true" else "false" | 53 | return if (b) "true" else "false"; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | 56 | ||
| ... | @@ -239,17 +239,17 @@ test "peer type resolution: error and [N]T" { | ... | @@ -239,17 +239,17 @@ test "peer type resolution: error and [N]T" { |
| 239 | 239 | ||
| 240 | error BadValue; | 240 | error BadValue; |
| 241 | fn testPeerErrorAndArray(x: u8) -> %[]const u8 { | 241 | fn testPeerErrorAndArray(x: u8) -> %[]const u8 { |
| 242 | switch (x) { | 242 | return switch (x) { |
| 243 | 0x00 => "OK", | 243 | 0x00 => "OK", |
| 244 | else => error.BadValue, | 244 | else => error.BadValue, |
| 245 | } | 245 | }; |
| 246 | } | 246 | } |
| 247 | fn testPeerErrorAndArray2(x: u8) -> %[]const u8 { | 247 | fn testPeerErrorAndArray2(x: u8) -> %[]const u8 { |
| 248 | switch (x) { | 248 | return switch (x) { |
| 249 | 0x00 => "OK", | 249 | 0x00 => "OK", |
| 250 | 0x01 => "OKK", | 250 | 0x01 => "OKK", |
| 251 | else => error.BadValue, | 251 | else => error.BadValue, |
| 252 | } | 252 | }; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | test "explicit cast float number literal to integer if no fraction component" { | 255 | test "explicit cast float number literal to integer if no fraction component" { |
| ... | @@ -269,11 +269,11 @@ fn testCast128() { | ... | @@ -269,11 +269,11 @@ fn testCast128() { |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | fn cast128Int(x: f128) -> u128 { | 271 | fn cast128Int(x: f128) -> u128 { |
| 272 | @bitCast(u128, x) | 272 | return @bitCast(u128, x); |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | fn cast128Float(x: u128) -> f128 { | 275 | fn cast128Float(x: u128) -> f128 { |
| 276 | @bitCast(f128, x) | 276 | return @bitCast(f128, x); |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | test "const slice widen cast" { | 279 | test "const slice widen cast" { |
test/cases/defer.zig+6-6| ... | @@ -7,9 +7,9 @@ error FalseNotAllowed; | ... | @@ -7,9 +7,9 @@ error FalseNotAllowed; |
| 7 | 7 | ||
| 8 | fn runSomeErrorDefers(x: bool) -> %bool { | 8 | fn runSomeErrorDefers(x: bool) -> %bool { |
| 9 | index = 0; | 9 | index = 0; |
| 10 | defer {result[index] = 'a'; index += 1;}; | 10 | defer {result[index] = 'a'; index += 1;} |
| 11 | %defer {result[index] = 'b'; index += 1;}; | 11 | %defer {result[index] = 'b'; index += 1;} |
| 12 | defer {result[index] = 'c'; index += 1;}; | 12 | defer {result[index] = 'c'; index += 1;} |
| 13 | return if (x) x else error.FalseNotAllowed; | 13 | return if (x) x else error.FalseNotAllowed; |
| 14 | } | 14 | } |
| 15 | 15 | ||
| ... | @@ -18,9 +18,9 @@ test "mixing normal and error defers" { | ... | @@ -18,9 +18,9 @@ test "mixing normal and error defers" { |
| 18 | assert(result[0] == 'c'); | 18 | assert(result[0] == 'c'); |
| 19 | assert(result[1] == 'a'); | 19 | assert(result[1] == 'a'); |
| 20 | 20 | ||
| 21 | const ok = runSomeErrorDefers(false) %% |err| { | 21 | const ok = runSomeErrorDefers(false) %% |err| x: { |
| 22 | assert(err == error.FalseNotAllowed); | 22 | assert(err == error.FalseNotAllowed); |
| 23 | true | 23 | break :x true; |
| 24 | }; | 24 | }; |
| 25 | assert(ok); | 25 | assert(ok); |
| 26 | assert(result[0] == 'c'); | 26 | assert(result[0] == 'c'); |
| ... | @@ -41,5 +41,5 @@ fn testBreakContInDefer(x: usize) { | ... | @@ -41,5 +41,5 @@ fn testBreakContInDefer(x: usize) { |
| 41 | if (i == 5) break; | 41 | if (i == 5) break; |
| 42 | } | 42 | } |
| 43 | assert(i == 5); | 43 | assert(i == 5); |
| 44 | }; | 44 | } |
| 45 | } | 45 | } |
test/cases/enum.zig+34-1| ... | @@ -41,7 +41,7 @@ const Bar = enum { | ... | @@ -41,7 +41,7 @@ const Bar = enum { |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | fn returnAnInt(x: i32) -> Foo { | 43 | fn returnAnInt(x: i32) -> Foo { |
| 44 | Foo { .One = x } | 44 | return Foo { .One = x }; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | 47 | ||
| ... | @@ -344,3 +344,36 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) { | ... | @@ -344,3 +344,36 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) { |
| 344 | MultipleChoice2.Unspecified5 => 9, | 344 | MultipleChoice2.Unspecified5 => 9, |
| 345 | }); | 345 | }); |
| 346 | } | 346 | } |
| 347 | |||
| 348 | test "cast integer literal to enum" { | ||
| 349 | assert(MultipleChoice2(0) == MultipleChoice2.Unspecified1); | ||
| 350 | assert(MultipleChoice2(40) == MultipleChoice2.B); | ||
| 351 | } | ||
| 352 | |||
| 353 | const EnumWithOneMember = enum { | ||
| 354 | Eof, | ||
| 355 | }; | ||
| 356 | |||
| 357 | fn doALoopThing(id: EnumWithOneMember) { | ||
| 358 | while (true) { | ||
| 359 | if (id == EnumWithOneMember.Eof) { | ||
| 360 | break; | ||
| 361 | } | ||
| 362 | @compileError("above if condition should be comptime"); | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | test "comparison operator on enum with one member is comptime known" { | ||
| 367 | doALoopThing(EnumWithOneMember.Eof); | ||
| 368 | } | ||
| 369 | |||
| 370 | const State = enum { | ||
| 371 | Start, | ||
| 372 | }; | ||
| 373 | test "switch on enum with one member is comptime known" { | ||
| 374 | var state = State.Start; | ||
| 375 | switch (state) { | ||
| 376 | State.Start => return, | ||
| 377 | } | ||
| 378 | @compileError("analysis should not reach here"); | ||
| 379 | } |
test/cases/enum_with_members.zig+3-3| ... | @@ -8,9 +8,9 @@ const ET = union(enum) { | ... | @@ -8,9 +8,9 @@ const ET = union(enum) { |
| 8 | 8 | ||
| 9 | pub fn print(a: &const ET, buf: []u8) -> %usize { | 9 | pub fn print(a: &const ET, buf: []u8) -> %usize { |
| 10 | return switch (*a) { | 10 | return switch (*a) { |
| 11 | ET.SINT => |x| { fmt.formatIntBuf(buf, x, 10, false, 0) }, | 11 | ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), |
| 12 | ET.UINT => |x| { fmt.formatIntBuf(buf, x, 10, false, 0) }, | 12 | ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), |
| 13 | } | 13 | }; |
| 14 | } | 14 | } |
| 15 | }; | 15 | }; |
| 16 | 16 |
test/cases/error.zig+5-9| ... | @@ -3,7 +3,7 @@ const mem = @import("std").mem; | ... | @@ -3,7 +3,7 @@ const mem = @import("std").mem; |
| 3 | 3 | ||
| 4 | pub fn foo() -> %i32 { | 4 | pub fn foo() -> %i32 { |
| 5 | const x = %return bar(); | 5 | const x = %return bar(); |
| 6 | return x + 1 | 6 | return x + 1; |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | pub fn bar() -> %i32 { | 9 | pub fn bar() -> %i32 { |
| ... | @@ -21,7 +21,7 @@ test "error wrapping" { | ... | @@ -21,7 +21,7 @@ test "error wrapping" { |
| 21 | 21 | ||
| 22 | error ItBroke; | 22 | error ItBroke; |
| 23 | fn gimmeItBroke() -> []const u8 { | 23 | fn gimmeItBroke() -> []const u8 { |
| 24 | @errorName(error.ItBroke) | 24 | return @errorName(error.ItBroke); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | test "@errorName" { | 27 | test "@errorName" { |
| ... | @@ -48,7 +48,7 @@ error AnError; | ... | @@ -48,7 +48,7 @@ error AnError; |
| 48 | error AnError; | 48 | error AnError; |
| 49 | error SecondError; | 49 | error SecondError; |
| 50 | fn shouldBeNotEqual(a: error, b: error) { | 50 | fn shouldBeNotEqual(a: error, b: error) { |
| 51 | if (a == b) unreachable | 51 | if (a == b) unreachable; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | 54 | ||
| ... | @@ -60,11 +60,7 @@ test "error binary operator" { | ... | @@ -60,11 +60,7 @@ test "error binary operator" { |
| 60 | } | 60 | } |
| 61 | error ItBroke; | 61 | error ItBroke; |
| 62 | fn errBinaryOperatorG(x: bool) -> %isize { | 62 | fn errBinaryOperatorG(x: bool) -> %isize { |
| 63 | if (x) { | 63 | return if (x) error.ItBroke else isize(10); |
| 64 | error.ItBroke | ||
| 65 | } else { | ||
| 66 | isize(10) | ||
| 67 | } | ||
| 68 | } | 64 | } |
| 69 | 65 | ||
| 70 | 66 | ||
| ... | @@ -72,7 +68,7 @@ test "unwrap simple value from error" { | ... | @@ -72,7 +68,7 @@ test "unwrap simple value from error" { |
| 72 | const i = %%unwrapSimpleValueFromErrorDo(); | 68 | const i = %%unwrapSimpleValueFromErrorDo(); |
| 73 | assert(i == 13); | 69 | assert(i == 13); |
| 74 | } | 70 | } |
| 75 | fn unwrapSimpleValueFromErrorDo() -> %isize { 13 } | 71 | fn unwrapSimpleValueFromErrorDo() -> %isize { return 13; } |
| 76 | 72 | ||
| 77 | 73 | ||
| 78 | test "error return in assignment" { | 74 | test "error return in assignment" { |
test/cases/eval.zig+13-13| ... | @@ -44,7 +44,7 @@ test "static function evaluation" { | ... | @@ -44,7 +44,7 @@ test "static function evaluation" { |
| 44 | assert(statically_added_number == 3); | 44 | assert(statically_added_number == 3); |
| 45 | } | 45 | } |
| 46 | const statically_added_number = staticAdd(1, 2); | 46 | const statically_added_number = staticAdd(1, 2); |
| 47 | fn staticAdd(a: i32, b: i32) -> i32 { a + b } | 47 | fn staticAdd(a: i32, b: i32) -> i32 { return a + b; } |
| 48 | 48 | ||
| 49 | 49 | ||
| 50 | test "const expr eval on single expr blocks" { | 50 | test "const expr eval on single expr blocks" { |
| ... | @@ -54,10 +54,10 @@ test "const expr eval on single expr blocks" { | ... | @@ -54,10 +54,10 @@ test "const expr eval on single expr blocks" { |
| 54 | fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) -> i32 { | 54 | fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) -> i32 { |
| 55 | const literal = 3; | 55 | const literal = 3; |
| 56 | 56 | ||
| 57 | const result = if (b) { | 57 | const result = if (b) b: { |
| 58 | literal | 58 | break :b literal; |
| 59 | } else { | 59 | } else b: { |
| 60 | x | 60 | break :b x; |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | return result; | 63 | return result; |
| ... | @@ -94,9 +94,9 @@ pub const Vec3 = struct { | ... | @@ -94,9 +94,9 @@ pub const Vec3 = struct { |
| 94 | data: [3]f32, | 94 | data: [3]f32, |
| 95 | }; | 95 | }; |
| 96 | pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 { | 96 | pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 { |
| 97 | Vec3 { | 97 | return Vec3 { |
| 98 | .data = []f32 { x, y, z, }, | 98 | .data = []f32 { x, y, z, }, |
| 99 | } | 99 | }; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | 102 | ||
| ... | @@ -176,7 +176,7 @@ fn max(comptime T: type, a: T, b: T) -> T { | ... | @@ -176,7 +176,7 @@ fn max(comptime T: type, a: T, b: T) -> T { |
| 176 | } | 176 | } |
| 177 | } | 177 | } |
| 178 | fn letsTryToCompareBools(a: bool, b: bool) -> bool { | 178 | fn letsTryToCompareBools(a: bool, b: bool) -> bool { |
| 179 | max(bool, a, b) | 179 | return max(bool, a, b); |
| 180 | } | 180 | } |
| 181 | test "inlined block and runtime block phi" { | 181 | test "inlined block and runtime block phi" { |
| 182 | assert(letsTryToCompareBools(true, true)); | 182 | assert(letsTryToCompareBools(true, true)); |
| ... | @@ -202,9 +202,9 @@ const cmd_fns = []CmdFn{ | ... | @@ -202,9 +202,9 @@ const cmd_fns = []CmdFn{ |
| 202 | CmdFn {.name = "two", .func = two}, | 202 | CmdFn {.name = "two", .func = two}, |
| 203 | CmdFn {.name = "three", .func = three}, | 203 | CmdFn {.name = "three", .func = three}, |
| 204 | }; | 204 | }; |
| 205 | fn one(value: i32) -> i32 { value + 1 } | 205 | fn one(value: i32) -> i32 { return value + 1; } |
| 206 | fn two(value: i32) -> i32 { value + 2 } | 206 | fn two(value: i32) -> i32 { return value + 2; } |
| 207 | fn three(value: i32) -> i32 { value + 3 } | 207 | fn three(value: i32) -> i32 { return value + 3; } |
| 208 | 208 | ||
| 209 | fn performFn(comptime prefix_char: u8, start_value: i32) -> i32 { | 209 | fn performFn(comptime prefix_char: u8, start_value: i32) -> i32 { |
| 210 | var result: i32 = start_value; | 210 | var result: i32 = start_value; |
| ... | @@ -317,12 +317,12 @@ test "create global array with for loop" { | ... | @@ -317,12 +317,12 @@ test "create global array with for loop" { |
| 317 | assert(global_array[9] == 9 * 9); | 317 | assert(global_array[9] == 9 * 9); |
| 318 | } | 318 | } |
| 319 | 319 | ||
| 320 | const global_array = { | 320 | const global_array = x: { |
| 321 | var result: [10]usize = undefined; | 321 | var result: [10]usize = undefined; |
| 322 | for (result) |*item, index| { | 322 | for (result) |*item, index| { |
| 323 | *item = index * index; | 323 | *item = index * index; |
| 324 | } | 324 | } |
| 325 | result | 325 | break :x result; |
| 326 | }; | 326 | }; |
| 327 | 327 | ||
| 328 | test "compile-time downcast when the bits fit" { | 328 | test "compile-time downcast when the bits fit" { |
test/cases/fn.zig+10-10| ... | @@ -4,7 +4,7 @@ test "params" { | ... | @@ -4,7 +4,7 @@ test "params" { |
| 4 | assert(testParamsAdd(22, 11) == 33); | 4 | assert(testParamsAdd(22, 11) == 33); |
| 5 | } | 5 | } |
| 6 | fn testParamsAdd(a: i32, b: i32) -> i32 { | 6 | fn testParamsAdd(a: i32, b: i32) -> i32 { |
| 7 | a + b | 7 | return a + b; |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | 10 | ||
| ... | @@ -22,7 +22,7 @@ test "void parameters" { | ... | @@ -22,7 +22,7 @@ test "void parameters" { |
| 22 | } | 22 | } |
| 23 | fn voidFun(a: i32, b: void, c: i32, d: void) { | 23 | fn voidFun(a: i32, b: void, c: i32, d: void) { |
| 24 | const v = b; | 24 | const v = b; |
| 25 | const vv: void = if (a == 1) {v} else {}; | 25 | const vv: void = if (a == 1) v else {}; |
| 26 | assert(a + c == 3); | 26 | assert(a + c == 3); |
| 27 | return vv; | 27 | return vv; |
| 28 | } | 28 | } |
| ... | @@ -45,9 +45,9 @@ test "separate block scopes" { | ... | @@ -45,9 +45,9 @@ test "separate block scopes" { |
| 45 | assert(no_conflict == 5); | 45 | assert(no_conflict == 5); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | const c = { | 48 | const c = x: { |
| 49 | const no_conflict = i32(10); | 49 | const no_conflict = i32(10); |
| 50 | no_conflict | 50 | break :x no_conflict; |
| 51 | }; | 51 | }; |
| 52 | assert(c == 10); | 52 | assert(c == 10); |
| 53 | } | 53 | } |
| ... | @@ -73,7 +73,7 @@ test "implicit cast function unreachable return" { | ... | @@ -73,7 +73,7 @@ test "implicit cast function unreachable return" { |
| 73 | fn wantsFnWithVoid(f: fn()) { } | 73 | fn wantsFnWithVoid(f: fn()) { } |
| 74 | 74 | ||
| 75 | fn fnWithUnreachable() -> noreturn { | 75 | fn fnWithUnreachable() -> noreturn { |
| 76 | unreachable | 76 | unreachable; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | 79 | ||
| ... | @@ -83,14 +83,14 @@ test "function pointers" { | ... | @@ -83,14 +83,14 @@ test "function pointers" { |
| 83 | assert(f() == u32(i) + 5); | 83 | assert(f() == u32(i) + 5); |
| 84 | } | 84 | } |
| 85 | } | 85 | } |
| 86 | fn fn1() -> u32 {5} | 86 | fn fn1() -> u32 {return 5;} |
| 87 | fn fn2() -> u32 {6} | 87 | fn fn2() -> u32 {return 6;} |
| 88 | fn fn3() -> u32 {7} | 88 | fn fn3() -> u32 {return 7;} |
| 89 | fn fn4() -> u32 {8} | 89 | fn fn4() -> u32 {return 8;} |
| 90 | 90 | ||
| 91 | 91 | ||
| 92 | test "inline function call" { | 92 | test "inline function call" { |
| 93 | assert(@inlineCall(add, 3, 9) == 12); | 93 | assert(@inlineCall(add, 3, 9) == 12); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | fn add(a: i32, b: i32) -> i32 { a + b } | 96 | fn add(a: i32, b: i32) -> i32 { return a + b; } |
test/cases/for.zig+35-1| ... | @@ -12,7 +12,7 @@ test "continue in for loop" { | ... | @@ -12,7 +12,7 @@ test "continue in for loop" { |
| 12 | } | 12 | } |
| 13 | break; | 13 | break; |
| 14 | } | 14 | } |
| 15 | if (sum != 6) unreachable | 15 | if (sum != 6) unreachable; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | test "for loop with pointer elem var" { | 18 | test "for loop with pointer elem var" { |
| ... | @@ -55,3 +55,37 @@ test "basic for loop" { | ... | @@ -55,3 +55,37 @@ test "basic for loop" { |
| 55 | 55 | ||
| 56 | assert(mem.eql(u8, buffer[0..buf_index], expected_result)); | 56 | assert(mem.eql(u8, buffer[0..buf_index], expected_result)); |
| 57 | } | 57 | } |
| 58 | |||
| 59 | test "break from outer for loop" { | ||
| 60 | testBreakOuter(); | ||
| 61 | comptime testBreakOuter(); | ||
| 62 | } | ||
| 63 | |||
| 64 | fn testBreakOuter() { | ||
| 65 | var array = "aoeu"; | ||
| 66 | var count: usize = 0; | ||
| 67 | outer: for (array) |_| { | ||
| 68 | for (array) |_2| { // TODO shouldn't get error for redeclaring "_" | ||
| 69 | count += 1; | ||
| 70 | break :outer; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | assert(count == 1); | ||
| 74 | } | ||
| 75 | |||
| 76 | test "continue outer for loop" { | ||
| 77 | testContinueOuter(); | ||
| 78 | comptime testContinueOuter(); | ||
| 79 | } | ||
| 80 | |||
| 81 | fn testContinueOuter() { | ||
| 82 | var array = "aoeu"; | ||
| 83 | var counter: usize = 0; | ||
| 84 | outer: for (array) |_| { | ||
| 85 | for (array) |_2| { // TODO shouldn't get error for redeclaring "_" | ||
| 86 | counter += 1; | ||
| 87 | continue :outer; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | assert(counter == array.len); | ||
| 91 | } |
test/cases/generics.zig+19-19| ... | @@ -11,7 +11,7 @@ fn max(comptime T: type, a: T, b: T) -> T { | ... | @@ -11,7 +11,7 @@ fn max(comptime T: type, a: T, b: T) -> T { |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | fn add(comptime a: i32, b: i32) -> i32 { | 13 | fn add(comptime a: i32, b: i32) -> i32 { |
| 14 | return (comptime {a}) + b; | 14 | return (comptime a) + b; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | const the_max = max(u32, 1234, 5678); | 17 | const the_max = max(u32, 1234, 5678); |
| ... | @@ -20,15 +20,15 @@ test "compile time generic eval" { | ... | @@ -20,15 +20,15 @@ test "compile time generic eval" { |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | fn gimmeTheBigOne(a: u32, b: u32) -> u32 { | 22 | fn gimmeTheBigOne(a: u32, b: u32) -> u32 { |
| 23 | max(u32, a, b) | 23 | return max(u32, a, b); |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | fn shouldCallSameInstance(a: u32, b: u32) -> u32 { | 26 | fn shouldCallSameInstance(a: u32, b: u32) -> u32 { |
| 27 | max(u32, a, b) | 27 | return max(u32, a, b); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | fn sameButWithFloats(a: f64, b: f64) -> f64 { | 30 | fn sameButWithFloats(a: f64, b: f64) -> f64 { |
| 31 | max(f64, a, b) | 31 | return max(f64, a, b); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | test "fn with comptime args" { | 34 | test "fn with comptime args" { |
| ... | @@ -49,28 +49,28 @@ comptime { | ... | @@ -49,28 +49,28 @@ comptime { |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | fn max_var(a: var, b: var) -> @typeOf(a + b) { | 51 | fn max_var(a: var, b: var) -> @typeOf(a + b) { |
| 52 | if (a > b) a else b | 52 | return if (a > b) a else b; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | fn max_i32(a: i32, b: i32) -> i32 { | 55 | fn max_i32(a: i32, b: i32) -> i32 { |
| 56 | max_var(a, b) | 56 | return max_var(a, b); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | fn max_f64(a: f64, b: f64) -> f64 { | 59 | fn max_f64(a: f64, b: f64) -> f64 { |
| 60 | max_var(a, b) | 60 | return max_var(a, b); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | 63 | ||
| 64 | pub fn List(comptime T: type) -> type { | 64 | pub fn List(comptime T: type) -> type { |
| 65 | SmallList(T, 8) | 65 | return SmallList(T, 8); |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type { | 68 | pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type { |
| 69 | struct { | 69 | return struct { |
| 70 | items: []T, | 70 | items: []T, |
| 71 | length: usize, | 71 | length: usize, |
| 72 | prealloc_items: [STATIC_SIZE]T, | 72 | prealloc_items: [STATIC_SIZE]T, |
| 73 | } | 73 | }; |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | test "function with return type type" { | 76 | test "function with return type type" { |
| ... | @@ -91,20 +91,20 @@ test "generic struct" { | ... | @@ -91,20 +91,20 @@ test "generic struct" { |
| 91 | assert(b1.getVal()); | 91 | assert(b1.getVal()); |
| 92 | } | 92 | } |
| 93 | fn GenNode(comptime T: type) -> type { | 93 | fn GenNode(comptime T: type) -> type { |
| 94 | struct { | 94 | return struct { |
| 95 | value: T, | 95 | value: T, |
| 96 | next: ?&GenNode(T), | 96 | next: ?&GenNode(T), |
| 97 | fn getVal(n: &const GenNode(T)) -> T { n.value } | 97 | fn getVal(n: &const GenNode(T)) -> T { return n.value; } |
| 98 | } | 98 | }; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | test "const decls in struct" { | 101 | test "const decls in struct" { |
| 102 | assert(GenericDataThing(3).count_plus_one == 4); | 102 | assert(GenericDataThing(3).count_plus_one == 4); |
| 103 | } | 103 | } |
| 104 | fn GenericDataThing(comptime count: isize) -> type { | 104 | fn GenericDataThing(comptime count: isize) -> type { |
| 105 | struct { | 105 | return struct { |
| 106 | const count_plus_one = count + 1; | 106 | const count_plus_one = count + 1; |
| 107 | } | 107 | }; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | 110 | ||
| ... | @@ -120,16 +120,16 @@ test "generic fn with implicit cast" { | ... | @@ -120,16 +120,16 @@ test "generic fn with implicit cast" { |
| 120 | assert(getFirstByte(u8, []u8 {13}) == 13); | 120 | assert(getFirstByte(u8, []u8 {13}) == 13); |
| 121 | assert(getFirstByte(u16, []u16 {0, 13}) == 0); | 121 | assert(getFirstByte(u16, []u16 {0, 13}) == 0); |
| 122 | } | 122 | } |
| 123 | fn getByte(ptr: ?&const u8) -> u8 {*??ptr} | 123 | fn getByte(ptr: ?&const u8) -> u8 {return *??ptr;} |
| 124 | fn getFirstByte(comptime T: type, mem: []const T) -> u8 { | 124 | fn getFirstByte(comptime T: type, mem: []const T) -> u8 { |
| 125 | getByte(@ptrCast(&const u8, &mem[0])) | 125 | return getByte(@ptrCast(&const u8, &mem[0])); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | 128 | ||
| 129 | const foos = []fn(var) -> bool { foo1, foo2 }; | 129 | const foos = []fn(var) -> bool { foo1, foo2 }; |
| 130 | 130 | ||
| 131 | fn foo1(arg: var) -> bool { arg } | 131 | fn foo1(arg: var) -> bool { return arg; } |
| 132 | fn foo2(arg: var) -> bool { !arg } | 132 | fn foo2(arg: var) -> bool { return !arg; } |
| 133 | 133 | ||
| 134 | test "array of generic fns" { | 134 | test "array of generic fns" { |
| 135 | assert(foos[0](true)); | 135 | assert(foos[0](true)); |
test/cases/goto.zig deleted-37| ... | @@ -1,37 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "goto and labels" { | ||
| 4 | gotoLoop(); | ||
| 5 | assert(goto_counter == 10); | ||
| 6 | } | ||
| 7 | fn gotoLoop() { | ||
| 8 | var i: i32 = 0; | ||
| 9 | goto cond; | ||
| 10 | loop: | ||
| 11 | i += 1; | ||
| 12 | cond: | ||
| 13 | if (!(i < 10)) goto end; | ||
| 14 | goto_counter += 1; | ||
| 15 | goto loop; | ||
| 16 | end: | ||
| 17 | } | ||
| 18 | var goto_counter: i32 = 0; | ||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | test "goto leave defer scope" { | ||
| 23 | testGotoLeaveDeferScope(true); | ||
| 24 | } | ||
| 25 | fn testGotoLeaveDeferScope(b: bool) { | ||
| 26 | var it_worked = false; | ||
| 27 | |||
| 28 | goto entry; | ||
| 29 | exit: | ||
| 30 | if (it_worked) { | ||
| 31 | return; | ||
| 32 | } | ||
| 33 | unreachable; | ||
| 34 | entry: | ||
| 35 | defer it_worked = true; | ||
| 36 | if (b) goto exit; | ||
| 37 | } | ||
test/cases/if.zig+3-3| ... | @@ -29,10 +29,10 @@ test "else if expression" { | ... | @@ -29,10 +29,10 @@ test "else if expression" { |
| 29 | } | 29 | } |
| 30 | fn elseIfExpressionF(c: u8) -> u8 { | 30 | fn elseIfExpressionF(c: u8) -> u8 { |
| 31 | if (c == 0) { | 31 | if (c == 0) { |
| 32 | 0 | 32 | return 0; |
| 33 | } else if (c == 1) { | 33 | } else if (c == 1) { |
| 34 | 1 | 34 | return 1; |
| 35 | } else { | 35 | } else { |
| 36 | u8(2) | 36 | return u8(2); |
| 37 | } | 37 | } |
| 38 | } | 38 | } |
test/cases/import/a_namespace.zig+1-1| ... | @@ -1 +1 @@ | ... | @@ -1 +1 @@ |
| 1 | pub fn foo() -> i32 { 1234 } | 1 | pub fn foo() -> i32 { return 1234; } |
test/cases/ir_block_deps.zig+2-2| ... | @@ -8,10 +8,10 @@ fn foo(id: u64) -> %i32 { | ... | @@ -8,10 +8,10 @@ fn foo(id: u64) -> %i32 { |
| 8 | return %return getErrInt(); | 8 | return %return getErrInt(); |
| 9 | }, | 9 | }, |
| 10 | else => error.ItBroke, | 10 | else => error.ItBroke, |
| 11 | } | 11 | }; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | fn getErrInt() -> %i32 { 0 } | 14 | fn getErrInt() -> %i32 { return 0; } |
| 15 | 15 | ||
| 16 | error ItBroke; | 16 | error ItBroke; |
| 17 | 17 |
test/cases/math.zig+11-11| ... | @@ -28,16 +28,16 @@ fn testDivision() { | ... | @@ -28,16 +28,16 @@ fn testDivision() { |
| 28 | assert(divTrunc(f32, -5.0, 3.0) == -1.0); | 28 | assert(divTrunc(f32, -5.0, 3.0) == -1.0); |
| 29 | } | 29 | } |
| 30 | fn div(comptime T: type, a: T, b: T) -> T { | 30 | fn div(comptime T: type, a: T, b: T) -> T { |
| 31 | a / b | 31 | return a / b; |
| 32 | } | 32 | } |
| 33 | fn divExact(comptime T: type, a: T, b: T) -> T { | 33 | fn divExact(comptime T: type, a: T, b: T) -> T { |
| 34 | @divExact(a, b) | 34 | return @divExact(a, b); |
| 35 | } | 35 | } |
| 36 | fn divFloor(comptime T: type, a: T, b: T) -> T { | 36 | fn divFloor(comptime T: type, a: T, b: T) -> T { |
| 37 | @divFloor(a, b) | 37 | return @divFloor(a, b); |
| 38 | } | 38 | } |
| 39 | fn divTrunc(comptime T: type, a: T, b: T) -> T { | 39 | fn divTrunc(comptime T: type, a: T, b: T) -> T { |
| 40 | @divTrunc(a, b) | 40 | return @divTrunc(a, b); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | test "@addWithOverflow" { | 43 | test "@addWithOverflow" { |
| ... | @@ -71,7 +71,7 @@ fn testClz() { | ... | @@ -71,7 +71,7 @@ fn testClz() { |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | fn clz(x: var) -> usize { | 73 | fn clz(x: var) -> usize { |
| 74 | @clz(x) | 74 | return @clz(x); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | test "@ctz" { | 77 | test "@ctz" { |
| ... | @@ -86,7 +86,7 @@ fn testCtz() { | ... | @@ -86,7 +86,7 @@ fn testCtz() { |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | fn ctz(x: var) -> usize { | 88 | fn ctz(x: var) -> usize { |
| 89 | @ctz(x) | 89 | return @ctz(x); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | test "assignment operators" { | 92 | test "assignment operators" { |
| ... | @@ -180,10 +180,10 @@ fn test_u64_div() { | ... | @@ -180,10 +180,10 @@ fn test_u64_div() { |
| 180 | assert(result.remainder == 100663296); | 180 | assert(result.remainder == 100663296); |
| 181 | } | 181 | } |
| 182 | fn divWithResult(a: u64, b: u64) -> DivResult { | 182 | fn divWithResult(a: u64, b: u64) -> DivResult { |
| 183 | DivResult { | 183 | return DivResult { |
| 184 | .quotient = a / b, | 184 | .quotient = a / b, |
| 185 | .remainder = a % b, | 185 | .remainder = a % b, |
| 186 | } | 186 | }; |
| 187 | } | 187 | } |
| 188 | const DivResult = struct { | 188 | const DivResult = struct { |
| 189 | quotient: u64, | 189 | quotient: u64, |
| ... | @@ -191,8 +191,8 @@ const DivResult = struct { | ... | @@ -191,8 +191,8 @@ const DivResult = struct { |
| 191 | }; | 191 | }; |
| 192 | 192 | ||
| 193 | test "binary not" { | 193 | test "binary not" { |
| 194 | assert(comptime {~u16(0b1010101010101010) == 0b0101010101010101}); | 194 | assert(comptime x: {break :x ~u16(0b1010101010101010) == 0b0101010101010101;}); |
| 195 | assert(comptime {~u64(2147483647) == 18446744071562067968}); | 195 | assert(comptime x: {break :x ~u64(2147483647) == 18446744071562067968;}); |
| 196 | testBinaryNot(0b1010101010101010); | 196 | testBinaryNot(0b1010101010101010); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| ... | @@ -331,7 +331,7 @@ test "f128" { | ... | @@ -331,7 +331,7 @@ test "f128" { |
| 331 | comptime test_f128(); | 331 | comptime test_f128(); |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | fn make_f128(x: f128) -> f128 { x } | 334 | fn make_f128(x: f128) -> f128 { return x; } |
| 335 | 335 | ||
| 336 | fn test_f128() { | 336 | fn test_f128() { |
| 337 | assert(@sizeOf(f128) == 16); | 337 | assert(@sizeOf(f128) == 16); |
test/cases/misc.zig+21-18| ... | @@ -12,8 +12,11 @@ test "empty function with comments" { | ... | @@ -12,8 +12,11 @@ test "empty function with comments" { |
| 12 | emptyFunctionWithComments(); | 12 | emptyFunctionWithComments(); |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | export fn disabledExternFn() { | 15 | comptime { |
| 16 | @setGlobalLinkage(disabledExternFn, builtin.GlobalLinkage.Internal); | 16 | @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal); |
| 17 | } | ||
| 18 | |||
| 19 | extern fn disabledExternFn() { | ||
| 17 | } | 20 | } |
| 18 | 21 | ||
| 19 | test "call disabled extern fn" { | 22 | test "call disabled extern fn" { |
| ... | @@ -107,17 +110,17 @@ fn testShortCircuit(f: bool, t: bool) { | ... | @@ -107,17 +110,17 @@ fn testShortCircuit(f: bool, t: bool) { |
| 107 | var hit_3 = f; | 110 | var hit_3 = f; |
| 108 | var hit_4 = f; | 111 | var hit_4 = f; |
| 109 | 112 | ||
| 110 | if (t or {assert(f); f}) { | 113 | if (t or x: {assert(f); break :x f;}) { |
| 111 | hit_1 = t; | 114 | hit_1 = t; |
| 112 | } | 115 | } |
| 113 | if (f or { hit_2 = t; f }) { | 116 | if (f or x: { hit_2 = t; break :x f; }) { |
| 114 | assert(f); | 117 | assert(f); |
| 115 | } | 118 | } |
| 116 | 119 | ||
| 117 | if (t and { hit_3 = t; f }) { | 120 | if (t and x: { hit_3 = t; break :x f; }) { |
| 118 | assert(f); | 121 | assert(f); |
| 119 | } | 122 | } |
| 120 | if (f and {assert(f); f}) { | 123 | if (f and x: {assert(f); break :x f;}) { |
| 121 | assert(f); | 124 | assert(f); |
| 122 | } else { | 125 | } else { |
| 123 | hit_4 = t; | 126 | hit_4 = t; |
| ... | @@ -132,11 +135,11 @@ test "truncate" { | ... | @@ -132,11 +135,11 @@ test "truncate" { |
| 132 | assert(testTruncate(0x10fd) == 0xfd); | 135 | assert(testTruncate(0x10fd) == 0xfd); |
| 133 | } | 136 | } |
| 134 | fn testTruncate(x: u32) -> u8 { | 137 | fn testTruncate(x: u32) -> u8 { |
| 135 | @truncate(u8, x) | 138 | return @truncate(u8, x); |
| 136 | } | 139 | } |
| 137 | 140 | ||
| 138 | fn first4KeysOfHomeRow() -> []const u8 { | 141 | fn first4KeysOfHomeRow() -> []const u8 { |
| 139 | "aoeu" | 142 | return "aoeu"; |
| 140 | } | 143 | } |
| 141 | 144 | ||
| 142 | test "return string from function" { | 145 | test "return string from function" { |
| ... | @@ -164,7 +167,7 @@ test "memcpy and memset intrinsics" { | ... | @@ -164,7 +167,7 @@ test "memcpy and memset intrinsics" { |
| 164 | } | 167 | } |
| 165 | 168 | ||
| 166 | test "builtin static eval" { | 169 | test "builtin static eval" { |
| 167 | const x : i32 = comptime {1 + 2 + 3}; | 170 | const x : i32 = comptime x: {break :x 1 + 2 + 3;}; |
| 168 | assert(x == comptime 6); | 171 | assert(x == comptime 6); |
| 169 | } | 172 | } |
| 170 | 173 | ||
| ... | @@ -187,7 +190,7 @@ test "slicing" { | ... | @@ -187,7 +190,7 @@ test "slicing" { |
| 187 | 190 | ||
| 188 | test "constant equal function pointers" { | 191 | test "constant equal function pointers" { |
| 189 | const alias = emptyFn; | 192 | const alias = emptyFn; |
| 190 | assert(comptime {emptyFn == alias}); | 193 | assert(comptime x: {break :x emptyFn == alias;}); |
| 191 | } | 194 | } |
| 192 | 195 | ||
| 193 | fn emptyFn() {} | 196 | fn emptyFn() {} |
| ... | @@ -277,14 +280,14 @@ test "cast small unsigned to larger signed" { | ... | @@ -277,14 +280,14 @@ test "cast small unsigned to larger signed" { |
| 277 | assert(castSmallUnsignedToLargerSigned1(200) == i16(200)); | 280 | assert(castSmallUnsignedToLargerSigned1(200) == i16(200)); |
| 278 | assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); | 281 | assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); |
| 279 | } | 282 | } |
| 280 | fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { x } | 283 | fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { return x; } |
| 281 | fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { x } | 284 | fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { return x; } |
| 282 | 285 | ||
| 283 | 286 | ||
| 284 | test "implicit cast after unreachable" { | 287 | test "implicit cast after unreachable" { |
| 285 | assert(outer() == 1234); | 288 | assert(outer() == 1234); |
| 286 | } | 289 | } |
| 287 | fn inner() -> i32 { 1234 } | 290 | fn inner() -> i32 { return 1234; } |
| 288 | fn outer() -> i64 { | 291 | fn outer() -> i64 { |
| 289 | return inner(); | 292 | return inner(); |
| 290 | } | 293 | } |
| ... | @@ -307,8 +310,8 @@ test "call result of if else expression" { | ... | @@ -307,8 +310,8 @@ test "call result of if else expression" { |
| 307 | fn f2(x: bool) -> []const u8 { | 310 | fn f2(x: bool) -> []const u8 { |
| 308 | return (if (x) fA else fB)(); | 311 | return (if (x) fA else fB)(); |
| 309 | } | 312 | } |
| 310 | fn fA() -> []const u8 { "a" } | 313 | fn fA() -> []const u8 { return "a"; } |
| 311 | fn fB() -> []const u8 { "b" } | 314 | fn fB() -> []const u8 { return "b"; } |
| 312 | 315 | ||
| 313 | 316 | ||
| 314 | test "const expression eval handling of variables" { | 317 | test "const expression eval handling of variables" { |
| ... | @@ -376,7 +379,7 @@ test "pointer comparison" { | ... | @@ -376,7 +379,7 @@ test "pointer comparison" { |
| 376 | assert(ptrEql(b, b)); | 379 | assert(ptrEql(b, b)); |
| 377 | } | 380 | } |
| 378 | fn ptrEql(a: &const []const u8, b: &const []const u8) -> bool { | 381 | fn ptrEql(a: &const []const u8, b: &const []const u8) -> bool { |
| 379 | a == b | 382 | return a == b; |
| 380 | } | 383 | } |
| 381 | 384 | ||
| 382 | 385 | ||
| ... | @@ -480,7 +483,7 @@ test "@typeId" { | ... | @@ -480,7 +483,7 @@ test "@typeId" { |
| 480 | assert(@typeId(AUnion) == Tid.Union); | 483 | assert(@typeId(AUnion) == Tid.Union); |
| 481 | assert(@typeId(fn()) == Tid.Fn); | 484 | assert(@typeId(fn()) == Tid.Fn); |
| 482 | assert(@typeId(@typeOf(builtin)) == Tid.Namespace); | 485 | assert(@typeId(@typeOf(builtin)) == Tid.Namespace); |
| 483 | assert(@typeId(@typeOf({this})) == Tid.Block); | 486 | assert(@typeId(@typeOf(x: {break :x this;})) == Tid.Block); |
| 484 | // TODO bound fn | 487 | // TODO bound fn |
| 485 | // TODO arg tuple | 488 | // TODO arg tuple |
| 486 | // TODO opaque | 489 | // TODO opaque |
| ... | @@ -504,7 +507,7 @@ test "@typeName" { | ... | @@ -504,7 +507,7 @@ test "@typeName" { |
| 504 | 507 | ||
| 505 | test "volatile load and store" { | 508 | test "volatile load and store" { |
| 506 | var number: i32 = 1234; | 509 | var number: i32 = 1234; |
| 507 | const ptr = &volatile number; | 510 | const ptr = (&volatile i32)(&number); |
| 508 | *ptr += 1; | 511 | *ptr += 1; |
| 509 | assert(*ptr == 1235); | 512 | assert(*ptr == 1235); |
| 510 | } | 513 | } |
test/cases/reflection.zig+1-1| ... | @@ -22,7 +22,7 @@ test "reflection: function return type, var args, and param types" { | ... | @@ -22,7 +22,7 @@ test "reflection: function return type, var args, and param types" { |
| 22 | } | 22 | } |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 } | 25 | fn dummy(a: bool, b: i32, c: f32) -> i32 { return 1234; } |
| 26 | fn dummy_varargs(args: ...) {} | 26 | fn dummy_varargs(args: ...) {} |
| 27 | 27 | ||
| 28 | test "reflection: struct member types and names" { | 28 | test "reflection: struct member types and names" { |
test/cases/slice.zig+19| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const assert = @import("std").debug.assert; | 1 | const assert = @import("std").debug.assert; |
| 2 | const mem = @import("std").mem; | ||
| 2 | 3 | ||
| 3 | const x = @intToPtr(&i32, 0x1000)[0..0x500]; | 4 | const x = @intToPtr(&i32, 0x1000)[0..0x500]; |
| 4 | const y = x[0x100..]; | 5 | const y = x[0x100..]; |
| ... | @@ -15,3 +16,21 @@ test "slice child property" { | ... | @@ -15,3 +16,21 @@ test "slice child property" { |
| 15 | var slice = array[0..]; | 16 | var slice = array[0..]; |
| 16 | assert(@typeOf(slice).Child == i32); | 17 | assert(@typeOf(slice).Child == i32); |
| 17 | } | 18 | } |
| 19 | |||
| 20 | test "debug safety lets us slice from len..len" { | ||
| 21 | var an_array = []u8{1, 2, 3}; | ||
| 22 | assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) -> []u8 { | ||
| 26 | return a_slice[start..end]; | ||
| 27 | } | ||
| 28 | |||
| 29 | test "implicitly cast array of size 0 to slice" { | ||
| 30 | var msg = []u8 {}; | ||
| 31 | assertLenIsZero(msg); | ||
| 32 | } | ||
| 33 | |||
| 34 | fn assertLenIsZero(msg: []const u8) { | ||
| 35 | assert(msg.len == 0); | ||
| 36 | } |
test/cases/struct.zig+34-9| ... | @@ -2,7 +2,7 @@ const assert = @import("std").debug.assert; | ... | @@ -2,7 +2,7 @@ const assert = @import("std").debug.assert; |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | const StructWithNoFields = struct { | 4 | const StructWithNoFields = struct { |
| 5 | fn add(a: i32, b: i32) -> i32 { a + b } | 5 | fn add(a: i32, b: i32) -> i32 { return a + b; } |
| 6 | }; | 6 | }; |
| 7 | const empty_global_instance = StructWithNoFields {}; | 7 | const empty_global_instance = StructWithNoFields {}; |
| 8 | 8 | ||
| ... | @@ -109,7 +109,7 @@ const Foo = struct { | ... | @@ -109,7 +109,7 @@ const Foo = struct { |
| 109 | ptr: fn() -> i32, | 109 | ptr: fn() -> i32, |
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | fn aFunc() -> i32 { 13 } | 112 | fn aFunc() -> i32 { return 13; } |
| 113 | 113 | ||
| 114 | fn callStructField(foo: &const Foo) -> i32 { | 114 | fn callStructField(foo: &const Foo) -> i32 { |
| 115 | return foo.ptr(); | 115 | return foo.ptr(); |
| ... | @@ -124,7 +124,7 @@ test "store member function in variable" { | ... | @@ -124,7 +124,7 @@ test "store member function in variable" { |
| 124 | } | 124 | } |
| 125 | const MemberFnTestFoo = struct { | 125 | const MemberFnTestFoo = struct { |
| 126 | x: i32, | 126 | x: i32, |
| 127 | fn member(foo: &const MemberFnTestFoo) -> i32 { foo.x } | 127 | fn member(foo: &const MemberFnTestFoo) -> i32 { return foo.x; } |
| 128 | }; | 128 | }; |
| 129 | 129 | ||
| 130 | 130 | ||
| ... | @@ -141,7 +141,7 @@ test "member functions" { | ... | @@ -141,7 +141,7 @@ test "member functions" { |
| 141 | const MemberFnRand = struct { | 141 | const MemberFnRand = struct { |
| 142 | seed: u32, | 142 | seed: u32, |
| 143 | pub fn getSeed(r: &const MemberFnRand) -> u32 { | 143 | pub fn getSeed(r: &const MemberFnRand) -> u32 { |
| 144 | r.seed | 144 | return r.seed; |
| 145 | } | 145 | } |
| 146 | }; | 146 | }; |
| 147 | 147 | ||
| ... | @@ -154,10 +154,10 @@ const Bar = struct { | ... | @@ -154,10 +154,10 @@ const Bar = struct { |
| 154 | y: i32, | 154 | y: i32, |
| 155 | }; | 155 | }; |
| 156 | fn makeBar(x: i32, y: i32) -> Bar { | 156 | fn makeBar(x: i32, y: i32) -> Bar { |
| 157 | Bar { | 157 | return Bar { |
| 158 | .x = x, | 158 | .x = x, |
| 159 | .y = y, | 159 | .y = y, |
| 160 | } | 160 | }; |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | test "empty struct method call" { | 163 | test "empty struct method call" { |
| ... | @@ -166,7 +166,7 @@ test "empty struct method call" { | ... | @@ -166,7 +166,7 @@ test "empty struct method call" { |
| 166 | } | 166 | } |
| 167 | const EmptyStruct = struct { | 167 | const EmptyStruct = struct { |
| 168 | fn method(es: &const EmptyStruct) -> i32 { | 168 | fn method(es: &const EmptyStruct) -> i32 { |
| 169 | 1234 | 169 | return 1234; |
| 170 | } | 170 | } |
| 171 | }; | 171 | }; |
| 172 | 172 | ||
| ... | @@ -176,14 +176,14 @@ test "return empty struct from fn" { | ... | @@ -176,14 +176,14 @@ test "return empty struct from fn" { |
| 176 | } | 176 | } |
| 177 | const EmptyStruct2 = struct {}; | 177 | const EmptyStruct2 = struct {}; |
| 178 | fn testReturnEmptyStructFromFn() -> EmptyStruct2 { | 178 | fn testReturnEmptyStructFromFn() -> EmptyStruct2 { |
| 179 | EmptyStruct2 {} | 179 | return EmptyStruct2 {}; |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | test "pass slice of empty struct to fn" { | 182 | test "pass slice of empty struct to fn" { |
| 183 | assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1); | 183 | assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1); |
| 184 | } | 184 | } |
| 185 | fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) -> usize { | 185 | fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) -> usize { |
| 186 | slice.len | 186 | return slice.len; |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | const APackedStruct = packed struct { | 189 | const APackedStruct = packed struct { |
| ... | @@ -379,3 +379,28 @@ const Nibbles = packed struct { | ... | @@ -379,3 +379,28 @@ const Nibbles = packed struct { |
| 379 | x: u4, | 379 | x: u4, |
| 380 | y: u4, | 380 | y: u4, |
| 381 | }; | 381 | }; |
| 382 | |||
| 383 | const Bitfields = packed struct { | ||
| 384 | f1: u16, | ||
| 385 | f2: u16, | ||
| 386 | f3: u8, | ||
| 387 | f4: u8, | ||
| 388 | f5: u4, | ||
| 389 | f6: u4, | ||
| 390 | f7: u8, | ||
| 391 | }; | ||
| 392 | |||
| 393 | test "native bit field understands endianness" { | ||
| 394 | var all: u64 = 0x7765443322221111; | ||
| 395 | var bytes: [8]u8 = undefined; | ||
| 396 | @memcpy(&bytes[0], @ptrCast(&u8, &all), 8); | ||
| 397 | var bitfields = *@ptrCast(&Bitfields, &bytes[0]); | ||
| 398 | |||
| 399 | assert(bitfields.f1 == 0x1111); | ||
| 400 | assert(bitfields.f2 == 0x2222); | ||
| 401 | assert(bitfields.f3 == 0x33); | ||
| 402 | assert(bitfields.f4 == 0x44); | ||
| 403 | assert(bitfields.f5 == 0x5); | ||
| 404 | assert(bitfields.f6 == 0x6); | ||
| 405 | assert(bitfields.f7 == 0x77); | ||
| 406 | } |
test/cases/switch.zig+9-9| ... | @@ -21,12 +21,12 @@ test "switch with all ranges" { | ... | @@ -21,12 +21,12 @@ test "switch with all ranges" { |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | fn testSwitchWithAllRanges(x: u32, y: u32) -> u32 { | 23 | fn testSwitchWithAllRanges(x: u32, y: u32) -> u32 { |
| 24 | switch (x) { | 24 | return switch (x) { |
| 25 | 0 ... 100 => 1, | 25 | 0 ... 100 => 1, |
| 26 | 101 ... 200 => 2, | 26 | 101 ... 200 => 2, |
| 27 | 201 ... 300 => 3, | 27 | 201 ... 300 => 3, |
| 28 | else => y, | 28 | else => y, |
| 29 | } | 29 | }; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | test "implicit comptime switch" { | 32 | test "implicit comptime switch" { |
| ... | @@ -132,7 +132,7 @@ test "switch with multiple expressions" { | ... | @@ -132,7 +132,7 @@ test "switch with multiple expressions" { |
| 132 | assert(x == 2); | 132 | assert(x == 2); |
| 133 | } | 133 | } |
| 134 | fn returnsFive() -> i32 { | 134 | fn returnsFive() -> i32 { |
| 135 | 5 | 135 | return 5; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | 138 | ||
| ... | @@ -161,10 +161,10 @@ test "switch on type" { | ... | @@ -161,10 +161,10 @@ test "switch on type" { |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | fn trueIfBoolFalseOtherwise(comptime T: type) -> bool { | 163 | fn trueIfBoolFalseOtherwise(comptime T: type) -> bool { |
| 164 | switch (T) { | 164 | return switch (T) { |
| 165 | bool => true, | 165 | bool => true, |
| 166 | else => false, | 166 | else => false, |
| 167 | } | 167 | }; |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | test "switch handles all cases of number" { | 170 | test "switch handles all cases of number" { |
| ... | @@ -186,22 +186,22 @@ fn testSwitchHandleAllCases() { | ... | @@ -186,22 +186,22 @@ fn testSwitchHandleAllCases() { |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | fn testSwitchHandleAllCasesExhaustive(x: u2) -> u2 { | 188 | fn testSwitchHandleAllCasesExhaustive(x: u2) -> u2 { |
| 189 | switch (x) { | 189 | return switch (x) { |
| 190 | 0 => u2(3), | 190 | 0 => u2(3), |
| 191 | 1 => 2, | 191 | 1 => 2, |
| 192 | 2 => 1, | 192 | 2 => 1, |
| 193 | 3 => 0, | 193 | 3 => 0, |
| 194 | } | 194 | }; |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | fn testSwitchHandleAllCasesRange(x: u8) -> u8 { | 197 | fn testSwitchHandleAllCasesRange(x: u8) -> u8 { |
| 198 | switch (x) { | 198 | return switch (x) { |
| 199 | 0 ... 100 => u8(0), | 199 | 0 ... 100 => u8(0), |
| 200 | 101 ... 200 => 1, | 200 | 101 ... 200 => 1, |
| 201 | 201, 203 => 2, | 201 | 201, 203 => 2, |
| 202 | 202 => 4, | 202 | 202 => 4, |
| 203 | 204 ... 255 => 3, | 203 | 204 ... 255 => 3, |
| 204 | } | 204 | }; |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | test "switch all prongs unreachable" { | 207 | test "switch all prongs unreachable" { |
test/cases/switch_prong_err_enum.zig+1-1| ... | @@ -18,7 +18,7 @@ fn doThing(form_id: u64) -> %FormValue { | ... | @@ -18,7 +18,7 @@ fn doThing(form_id: u64) -> %FormValue { |
| 18 | return switch (form_id) { | 18 | return switch (form_id) { |
| 19 | 17 => FormValue { .Address = %return readOnce() }, | 19 | 17 => FormValue { .Address = %return readOnce() }, |
| 20 | else => error.InvalidDebugInfo, | 20 | else => error.InvalidDebugInfo, |
| 21 | } | 21 | }; |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | test "switch prong returns error enum" { | 24 | test "switch prong returns error enum" { |
test/cases/switch_prong_implicit_cast.zig+2-2| ... | @@ -8,11 +8,11 @@ const FormValue = union(enum) { | ... | @@ -8,11 +8,11 @@ const FormValue = union(enum) { |
| 8 | error Whatever; | 8 | error Whatever; |
| 9 | 9 | ||
| 10 | fn foo(id: u64) -> %FormValue { | 10 | fn foo(id: u64) -> %FormValue { |
| 11 | switch (id) { | 11 | return switch (id) { |
| 12 | 2 => FormValue { .Two = true }, | 12 | 2 => FormValue { .Two = true }, |
| 13 | 1 => FormValue { .One = {} }, | 13 | 1 => FormValue { .One = {} }, |
| 14 | else => return error.Whatever, | 14 | else => return error.Whatever, |
| 15 | } | 15 | }; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | test "switch prong implicit cast" { | 18 | test "switch prong implicit cast" { |
test/cases/this.zig+4-8| ... | @@ -3,7 +3,7 @@ const assert = @import("std").debug.assert; | ... | @@ -3,7 +3,7 @@ const assert = @import("std").debug.assert; |
| 3 | const module = this; | 3 | const module = this; |
| 4 | 4 | ||
| 5 | fn Point(comptime T: type) -> type { | 5 | fn Point(comptime T: type) -> type { |
| 6 | struct { | 6 | return struct { |
| 7 | const Self = this; | 7 | const Self = this; |
| 8 | x: T, | 8 | x: T, |
| 9 | y: T, | 9 | y: T, |
| ... | @@ -12,20 +12,16 @@ fn Point(comptime T: type) -> type { | ... | @@ -12,20 +12,16 @@ fn Point(comptime T: type) -> type { |
| 12 | self.x += 1; | 12 | self.x += 1; |
| 13 | self.y += 1; | 13 | self.y += 1; |
| 14 | } | 14 | } |
| 15 | } | 15 | }; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | fn add(x: i32, y: i32) -> i32 { | 18 | fn add(x: i32, y: i32) -> i32 { |
| 19 | x + y | 19 | return x + y; |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | fn factorial(x: i32) -> i32 { | 22 | fn factorial(x: i32) -> i32 { |
| 23 | const selfFn = this; | 23 | const selfFn = this; |
| 24 | if (x == 0) { | 24 | return if (x == 0) 1 else x * selfFn(x - 1); |
| 25 | 1 | ||
| 26 | } else { | ||
| 27 | x * selfFn(x - 1) | ||
| 28 | } | ||
| 29 | } | 25 | } |
| 30 | 26 | ||
| 31 | test "this refer to module call private fn" { | 27 | test "this refer to module call private fn" { |
test/cases/try.zig+5-13| ... | @@ -7,9 +7,9 @@ test "try on error union" { | ... | @@ -7,9 +7,9 @@ test "try on error union" { |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | fn tryOnErrorUnionImpl() { | 9 | fn tryOnErrorUnionImpl() { |
| 10 | const x = if (returnsTen()) |val| { | 10 | const x = if (returnsTen()) |val| |
| 11 | val + 1 | 11 | val + 1 |
| 12 | } else |err| switch (err) { | 12 | else |err| switch (err) { |
| 13 | error.ItBroke, error.NoMem => 1, | 13 | error.ItBroke, error.NoMem => 1, |
| 14 | error.CrappedOut => i32(2), | 14 | error.CrappedOut => i32(2), |
| 15 | else => unreachable, | 15 | else => unreachable, |
| ... | @@ -21,22 +21,14 @@ error ItBroke; | ... | @@ -21,22 +21,14 @@ error ItBroke; |
| 21 | error NoMem; | 21 | error NoMem; |
| 22 | error CrappedOut; | 22 | error CrappedOut; |
| 23 | fn returnsTen() -> %i32 { | 23 | fn returnsTen() -> %i32 { |
| 24 | 10 | 24 | return 10; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | test "try without vars" { | 27 | test "try without vars" { |
| 28 | const result1 = if (failIfTrue(true)) { | 28 | const result1 = if (failIfTrue(true)) 1 else |_| i32(2); |
| 29 | 1 | ||
| 30 | } else |_| { | ||
| 31 | i32(2) | ||
| 32 | }; | ||
| 33 | assert(result1 == 2); | 29 | assert(result1 == 2); |
| 34 | 30 | ||
| 35 | const result2 = if (failIfTrue(false)) { | 31 | const result2 = if (failIfTrue(false)) 1 else |_| i32(2); |
| 36 | 1 | ||
| 37 | } else |_| { | ||
| 38 | i32(2) | ||
| 39 | }; | ||
| 40 | assert(result2 == 1); | 32 | assert(result2 == 1); |
| 41 | } | 33 | } |
| 42 | 34 |
test/cases/union.zig+30| ... | @@ -190,3 +190,33 @@ test "cast union to tag type of union" { | ... | @@ -190,3 +190,33 @@ test "cast union to tag type of union" { |
| 190 | fn testCastUnionToTagType(x: &const TheUnion) { | 190 | fn testCastUnionToTagType(x: &const TheUnion) { |
| 191 | assert(TheTag(*x) == TheTag.B); | 191 | assert(TheTag(*x) == TheTag.B); |
| 192 | } | 192 | } |
| 193 | |||
| 194 | test "cast tag type of union to union" { | ||
| 195 | var x: Value2 = Letter2.B; | ||
| 196 | assert(Letter2(x) == Letter2.B); | ||
| 197 | } | ||
| 198 | const Letter2 = enum { A, B, C }; | ||
| 199 | const Value2 = union(Letter2) { A: i32, B, C, }; | ||
| 200 | |||
| 201 | test "implicit cast union to its tag type" { | ||
| 202 | var x: Value2 = Letter2.B; | ||
| 203 | assert(x == Letter2.B); | ||
| 204 | giveMeLetterB(x); | ||
| 205 | } | ||
| 206 | fn giveMeLetterB(x: Letter2) { | ||
| 207 | assert(x == Value2.B); | ||
| 208 | } | ||
| 209 | |||
| 210 | test "implicit cast from @EnumTagType(TheUnion) to &const TheUnion" { | ||
| 211 | assertIsTheUnion2Item1(TheUnion2.Item1); | ||
| 212 | } | ||
| 213 | |||
| 214 | const TheUnion2 = union(enum) { | ||
| 215 | Item1, | ||
| 216 | Item2: i32, | ||
| 217 | }; | ||
| 218 | |||
| 219 | fn assertIsTheUnion2Item1(value: &const TheUnion2) { | ||
| 220 | assert(*value == TheUnion2.Item1); | ||
| 221 | } | ||
| 222 |
test/cases/var_args.zig+2-2| ... | @@ -58,8 +58,8 @@ fn extraFn(extra: u32, args: ...) -> usize { | ... | @@ -58,8 +58,8 @@ fn extraFn(extra: u32, args: ...) -> usize { |
| 58 | 58 | ||
| 59 | const foos = []fn(...) -> bool { foo1, foo2 }; | 59 | const foos = []fn(...) -> bool { foo1, foo2 }; |
| 60 | 60 | ||
| 61 | fn foo1(args: ...) -> bool { true } | 61 | fn foo1(args: ...) -> bool { return true; } |
| 62 | fn foo2(args: ...) -> bool { false } | 62 | fn foo2(args: ...) -> bool { return false; } |
| 63 | 63 | ||
| 64 | test "array of var args functions" { | 64 | test "array of var args functions" { |
| 65 | assert(foos[0]()); | 65 | assert(foos[0]()); |
test/cases/while.zig+45-30| ... | @@ -118,80 +118,95 @@ test "while with error union condition" { | ... | @@ -118,80 +118,95 @@ test "while with error union condition" { |
| 118 | var numbers_left: i32 = undefined; | 118 | var numbers_left: i32 = undefined; |
| 119 | error OutOfNumbers; | 119 | error OutOfNumbers; |
| 120 | fn getNumberOrErr() -> %i32 { | 120 | fn getNumberOrErr() -> %i32 { |
| 121 | return if (numbers_left == 0) { | 121 | return if (numbers_left == 0) |
| 122 | error.OutOfNumbers | 122 | error.OutOfNumbers |
| 123 | } else { | 123 | else x: { |
| 124 | numbers_left -= 1; | 124 | numbers_left -= 1; |
| 125 | numbers_left | 125 | break :x numbers_left; |
| 126 | }; | 126 | }; |
| 127 | } | 127 | } |
| 128 | fn getNumberOrNull() -> ?i32 { | 128 | fn getNumberOrNull() -> ?i32 { |
| 129 | return if (numbers_left == 0) { | 129 | return if (numbers_left == 0) |
| 130 | null | 130 | null |
| 131 | } else { | 131 | else x: { |
| 132 | numbers_left -= 1; | 132 | numbers_left -= 1; |
| 133 | numbers_left | 133 | break :x numbers_left; |
| 134 | }; | 134 | }; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | test "while on nullable with else result follow else prong" { | 137 | test "while on nullable with else result follow else prong" { |
| 138 | const result = while (returnNull()) |value| { | 138 | const result = while (returnNull()) |value| { |
| 139 | break value; | 139 | break value; |
| 140 | } else { | 140 | } else i32(2); |
| 141 | i32(2) | ||
| 142 | }; | ||
| 143 | assert(result == 2); | 141 | assert(result == 2); |
| 144 | } | 142 | } |
| 145 | 143 | ||
| 146 | test "while on nullable with else result follow break prong" { | 144 | test "while on nullable with else result follow break prong" { |
| 147 | const result = while (returnMaybe(10)) |value| { | 145 | const result = while (returnMaybe(10)) |value| { |
| 148 | break value; | 146 | break value; |
| 149 | } else { | 147 | } else i32(2); |
| 150 | i32(2) | ||
| 151 | }; | ||
| 152 | assert(result == 10); | 148 | assert(result == 10); |
| 153 | } | 149 | } |
| 154 | 150 | ||
| 155 | test "while on error union with else result follow else prong" { | 151 | test "while on error union with else result follow else prong" { |
| 156 | const result = while (returnError()) |value| { | 152 | const result = while (returnError()) |value| { |
| 157 | break value; | 153 | break value; |
| 158 | } else |err| { | 154 | } else |err| i32(2); |
| 159 | i32(2) | ||
| 160 | }; | ||
| 161 | assert(result == 2); | 155 | assert(result == 2); |
| 162 | } | 156 | } |
| 163 | 157 | ||
| 164 | test "while on error union with else result follow break prong" { | 158 | test "while on error union with else result follow break prong" { |
| 165 | const result = while (returnSuccess(10)) |value| { | 159 | const result = while (returnSuccess(10)) |value| { |
| 166 | break value; | 160 | break value; |
| 167 | } else |err| { | 161 | } else |err| i32(2); |
| 168 | i32(2) | ||
| 169 | }; | ||
| 170 | assert(result == 10); | 162 | assert(result == 10); |
| 171 | } | 163 | } |
| 172 | 164 | ||
| 173 | test "while on bool with else result follow else prong" { | 165 | test "while on bool with else result follow else prong" { |
| 174 | const result = while (returnFalse()) { | 166 | const result = while (returnFalse()) { |
| 175 | break i32(10); | 167 | break i32(10); |
| 176 | } else { | 168 | } else i32(2); |
| 177 | i32(2) | ||
| 178 | }; | ||
| 179 | assert(result == 2); | 169 | assert(result == 2); |
| 180 | } | 170 | } |
| 181 | 171 | ||
| 182 | test "while on bool with else result follow break prong" { | 172 | test "while on bool with else result follow break prong" { |
| 183 | const result = while (returnTrue()) { | 173 | const result = while (returnTrue()) { |
| 184 | break i32(10); | 174 | break i32(10); |
| 185 | } else { | 175 | } else i32(2); |
| 186 | i32(2) | ||
| 187 | }; | ||
| 188 | assert(result == 10); | 176 | assert(result == 10); |
| 189 | } | 177 | } |
| 190 | 178 | ||
| 191 | fn returnNull() -> ?i32 { null } | 179 | test "break from outer while loop" { |
| 192 | fn returnMaybe(x: i32) -> ?i32 { x } | 180 | testBreakOuter(); |
| 181 | comptime testBreakOuter(); | ||
| 182 | } | ||
| 183 | |||
| 184 | fn testBreakOuter() { | ||
| 185 | outer: while (true) { | ||
| 186 | while (true) { | ||
| 187 | break :outer; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | test "continue outer while loop" { | ||
| 193 | testContinueOuter(); | ||
| 194 | comptime testContinueOuter(); | ||
| 195 | } | ||
| 196 | |||
| 197 | fn testContinueOuter() { | ||
| 198 | var i: usize = 0; | ||
| 199 | outer: while (i < 10) : (i += 1) { | ||
| 200 | while (true) { | ||
| 201 | continue :outer; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | fn returnNull() -> ?i32 { return null; } | ||
| 207 | fn returnMaybe(x: i32) -> ?i32 { return x; } | ||
| 193 | error YouWantedAnError; | 208 | error YouWantedAnError; |
| 194 | fn returnError() -> %i32 { error.YouWantedAnError } | 209 | fn returnError() -> %i32 { return error.YouWantedAnError; } |
| 195 | fn returnSuccess(x: i32) -> %i32 { x } | 210 | fn returnSuccess(x: i32) -> %i32 { return x; } |
| 196 | fn returnFalse() -> bool { false } | 211 | fn returnFalse() -> bool { return false; } |
| 197 | fn returnTrue() -> bool { true } | 212 | fn returnTrue() -> bool { return true; } |
test/compare_output.zig+95-13| ... | @@ -10,7 +10,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -10,7 +10,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 10 | \\} | 10 | \\} |
| 11 | , "Hello, world!" ++ os.line_sep); | 11 | , "Hello, world!" ++ os.line_sep); |
| 12 | 12 | ||
| 13 | cases.addCase({ | 13 | cases.addCase(x: { |
| 14 | var tc = cases.create("multiple files with private function", | 14 | var tc = cases.create("multiple files with private function", |
| 15 | \\use @import("std").io; | 15 | \\use @import("std").io; |
| 16 | \\use @import("foo.zig"); | 16 | \\use @import("foo.zig"); |
| ... | @@ -41,10 +41,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -41,10 +41,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 41 | \\} | 41 | \\} |
| 42 | ); | 42 | ); |
| 43 | 43 | ||
| 44 | tc | 44 | break :x tc; |
| 45 | }); | 45 | }); |
| 46 | 46 | ||
| 47 | cases.addCase({ | 47 | cases.addCase(x: { |
| 48 | var tc = cases.create("import segregation", | 48 | var tc = cases.create("import segregation", |
| 49 | \\use @import("foo.zig"); | 49 | \\use @import("foo.zig"); |
| 50 | \\use @import("bar.zig"); | 50 | \\use @import("bar.zig"); |
| ... | @@ -82,10 +82,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -82,10 +82,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 82 | \\} | 82 | \\} |
| 83 | ); | 83 | ); |
| 84 | 84 | ||
| 85 | tc | 85 | break :x tc; |
| 86 | }); | 86 | }); |
| 87 | 87 | ||
| 88 | cases.addCase({ | 88 | cases.addCase(x: { |
| 89 | var tc = cases.create("two files use import each other", | 89 | var tc = cases.create("two files use import each other", |
| 90 | \\use @import("a.zig"); | 90 | \\use @import("a.zig"); |
| 91 | \\ | 91 | \\ |
| ... | @@ -112,7 +112,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -112,7 +112,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 112 | \\pub const b_text = a_text; | 112 | \\pub const b_text = a_text; |
| 113 | ); | 113 | ); |
| 114 | 114 | ||
| 115 | tc | 115 | break :x tc; |
| 116 | }); | 116 | }); |
| 117 | 117 | ||
| 118 | cases.add("hello world without libc", | 118 | cases.add("hello world without libc", |
| ... | @@ -286,11 +286,11 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -286,11 +286,11 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 286 | \\ const a_int = @ptrCast(&align(1) i32, a ?? unreachable); | 286 | \\ const a_int = @ptrCast(&align(1) i32, a ?? unreachable); |
| 287 | \\ const b_int = @ptrCast(&align(1) i32, b ?? unreachable); | 287 | \\ const b_int = @ptrCast(&align(1) i32, b ?? unreachable); |
| 288 | \\ if (*a_int < *b_int) { | 288 | \\ if (*a_int < *b_int) { |
| 289 | \\ -1 | 289 | \\ return -1; |
| 290 | \\ } else if (*a_int > *b_int) { | 290 | \\ } else if (*a_int > *b_int) { |
| 291 | \\ 1 | 291 | \\ return 1; |
| 292 | \\ } else { | 292 | \\ } else { |
| 293 | \\ c_int(0) | 293 | \\ return 0; |
| 294 | \\ } | 294 | \\ } |
| 295 | \\} | 295 | \\} |
| 296 | \\ | 296 | \\ |
| ... | @@ -342,13 +342,13 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -342,13 +342,13 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 342 | \\const Foo = struct { | 342 | \\const Foo = struct { |
| 343 | \\ field1: Bar, | 343 | \\ field1: Bar, |
| 344 | \\ | 344 | \\ |
| 345 | \\ fn method(a: &const Foo) -> bool { true } | 345 | \\ fn method(a: &const Foo) -> bool { return true; } |
| 346 | \\}; | 346 | \\}; |
| 347 | \\ | 347 | \\ |
| 348 | \\const Bar = struct { | 348 | \\const Bar = struct { |
| 349 | \\ field2: i32, | 349 | \\ field2: i32, |
| 350 | \\ | 350 | \\ |
| 351 | \\ fn method(b: &const Bar) -> bool { true } | 351 | \\ fn method(b: &const Bar) -> bool { return true; } |
| 352 | \\}; | 352 | \\}; |
| 353 | \\ | 353 | \\ |
| 354 | \\pub fn main() -> %void { | 354 | \\pub fn main() -> %void { |
| ... | @@ -429,7 +429,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -429,7 +429,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 429 | \\fn its_gonna_pass() -> %void { } | 429 | \\fn its_gonna_pass() -> %void { } |
| 430 | , "before\nafter\ndefer3\ndefer1\n"); | 430 | , "before\nafter\ndefer3\ndefer1\n"); |
| 431 | 431 | ||
| 432 | cases.addCase({ | 432 | cases.addCase(x: { |
| 433 | var tc = cases.create("@embedFile", | 433 | var tc = cases.create("@embedFile", |
| 434 | \\const foo_txt = @embedFile("foo.txt"); | 434 | \\const foo_txt = @embedFile("foo.txt"); |
| 435 | \\const io = @import("std").io; | 435 | \\const io = @import("std").io; |
| ... | @@ -442,6 +442,88 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -442,6 +442,88 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 442 | 442 | ||
| 443 | tc.addSourceFile("foo.txt", "1234\nabcd\n"); | 443 | tc.addSourceFile("foo.txt", "1234\nabcd\n"); |
| 444 | 444 | ||
| 445 | tc | 445 | break :x tc; |
| 446 | }); | ||
| 447 | |||
| 448 | cases.addCase(x: { | ||
| 449 | var tc = cases.create("parsing args", | ||
| 450 | \\const std = @import("std"); | ||
| 451 | \\const io = std.io; | ||
| 452 | \\const os = std.os; | ||
| 453 | \\const allocator = std.debug.global_allocator; | ||
| 454 | \\ | ||
| 455 | \\pub fn main() -> %void { | ||
| 456 | \\ var args_it = os.args(); | ||
| 457 | \\ var stdout_file = %return io.getStdOut(); | ||
| 458 | \\ var stdout_adapter = io.FileOutStream.init(&stdout_file); | ||
| 459 | \\ const stdout = &stdout_adapter.stream; | ||
| 460 | \\ var index: usize = 0; | ||
| 461 | \\ _ = args_it.skip(); | ||
| 462 | \\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) { | ||
| 463 | \\ const arg = %return arg_or_err; | ||
| 464 | \\ %return stdout.print("{}: {}\n", index, arg); | ||
| 465 | \\ } | ||
| 466 | \\} | ||
| 467 | , | ||
| 468 | \\0: first arg | ||
| 469 | \\1: 'a' 'b' \ | ||
| 470 | \\2: bare | ||
| 471 | \\3: ba""re | ||
| 472 | \\4: " | ||
| 473 | \\5: last arg | ||
| 474 | \\ | ||
| 475 | ); | ||
| 476 | |||
| 477 | tc.setCommandLineArgs([][]const u8 { | ||
| 478 | "first arg", | ||
| 479 | "'a' 'b' \\", | ||
| 480 | "bare", | ||
| 481 | "ba\"\"re", | ||
| 482 | "\"", | ||
| 483 | "last arg", | ||
| 484 | }); | ||
| 485 | |||
| 486 | break :x tc; | ||
| 487 | }); | ||
| 488 | |||
| 489 | cases.addCase(x: { | ||
| 490 | var tc = cases.create("parsing args new API", | ||
| 491 | \\const std = @import("std"); | ||
| 492 | \\const io = std.io; | ||
| 493 | \\const os = std.os; | ||
| 494 | \\const allocator = std.debug.global_allocator; | ||
| 495 | \\ | ||
| 496 | \\pub fn main() -> %void { | ||
| 497 | \\ var args_it = os.args(); | ||
| 498 | \\ var stdout_file = %return io.getStdOut(); | ||
| 499 | \\ var stdout_adapter = io.FileOutStream.init(&stdout_file); | ||
| 500 | \\ const stdout = &stdout_adapter.stream; | ||
| 501 | \\ var index: usize = 0; | ||
| 502 | \\ _ = args_it.skip(); | ||
| 503 | \\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) { | ||
| 504 | \\ const arg = %return arg_or_err; | ||
| 505 | \\ %return stdout.print("{}: {}\n", index, arg); | ||
| 506 | \\ } | ||
| 507 | \\} | ||
| 508 | , | ||
| 509 | \\0: first arg | ||
| 510 | \\1: 'a' 'b' \ | ||
| 511 | \\2: bare | ||
| 512 | \\3: ba""re | ||
| 513 | \\4: " | ||
| 514 | \\5: last arg | ||
| 515 | \\ | ||
| 516 | ); | ||
| 517 | |||
| 518 | tc.setCommandLineArgs([][]const u8 { | ||
| 519 | "first arg", | ||
| 520 | "'a' 'b' \\", | ||
| 521 | "bare", | ||
| 522 | "ba\"\"re", | ||
| 523 | "\"", | ||
| 524 | "last arg", | ||
| 525 | }); | ||
| 526 | |||
| 527 | break :x tc; | ||
| 446 | }); | 528 | }); |
| 447 | } | 529 | } |
test/compile_errors.zig+276-224| ... | @@ -1,6 +1,37 @@ | ... | @@ -1,6 +1,37 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: &tests.CompileErrorContext) { | 3 | pub fn addCases(cases: &tests.CompileErrorContext) { |
| 4 | cases.add("labeled break not found", | ||
| 5 | \\export fn entry() { | ||
| 6 | \\ blah: while (true) { | ||
| 7 | \\ while (true) { | ||
| 8 | \\ break :outer; | ||
| 9 | \\ } | ||
| 10 | \\ } | ||
| 11 | \\} | ||
| 12 | , ".tmp_source.zig:4:13: error: label not found: 'outer'"); | ||
| 13 | |||
| 14 | cases.add("labeled continue not found", | ||
| 15 | \\export fn entry() { | ||
| 16 | \\ var i: usize = 0; | ||
| 17 | \\ blah: while (i < 10) : (i += 1) { | ||
| 18 | \\ while (true) { | ||
| 19 | \\ continue :outer; | ||
| 20 | \\ } | ||
| 21 | \\ } | ||
| 22 | \\} | ||
| 23 | , ".tmp_source.zig:5:13: error: labeled loop not found: 'outer'"); | ||
| 24 | |||
| 25 | cases.add("attempt to use 0 bit type in extern fn", | ||
| 26 | \\extern fn foo(ptr: extern fn(&void)); | ||
| 27 | \\ | ||
| 28 | \\export fn entry() { | ||
| 29 | \\ foo(bar); | ||
| 30 | \\} | ||
| 31 | \\ | ||
| 32 | \\extern fn bar(x: &void) { } | ||
| 33 | , ".tmp_source.zig:7:18: error: parameter of type '&void' has 0 bits; not allowed in function with calling convention 'ccc'"); | ||
| 34 | |||
| 4 | cases.add("implicit semicolon - block statement", | 35 | cases.add("implicit semicolon - block statement", |
| 5 | \\export fn entry() { | 36 | \\export fn entry() { |
| 6 | \\ {} | 37 | \\ {} |
| ... | @@ -8,7 +39,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -8,7 +39,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 8 | \\ ({}) | 39 | \\ ({}) |
| 9 | \\ var bad = {}; | 40 | \\ var bad = {}; |
| 10 | \\} | 41 | \\} |
| 11 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 42 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 12 | 43 | ||
| 13 | cases.add("implicit semicolon - block expr", | 44 | cases.add("implicit semicolon - block expr", |
| 14 | \\export fn entry() { | 45 | \\export fn entry() { |
| ... | @@ -17,7 +48,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -17,7 +48,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 17 | \\ _ = {} | 48 | \\ _ = {} |
| 18 | \\ var bad = {}; | 49 | \\ var bad = {}; |
| 19 | \\} | 50 | \\} |
| 20 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 51 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 21 | 52 | ||
| 22 | cases.add("implicit semicolon - comptime statement", | 53 | cases.add("implicit semicolon - comptime statement", |
| 23 | \\export fn entry() { | 54 | \\export fn entry() { |
| ... | @@ -26,7 +57,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -26,7 +57,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 26 | \\ comptime ({}) | 57 | \\ comptime ({}) |
| 27 | \\ var bad = {}; | 58 | \\ var bad = {}; |
| 28 | \\} | 59 | \\} |
| 29 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 60 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 30 | 61 | ||
| 31 | cases.add("implicit semicolon - comptime expression", | 62 | cases.add("implicit semicolon - comptime expression", |
| 32 | \\export fn entry() { | 63 | \\export fn entry() { |
| ... | @@ -35,7 +66,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -35,7 +66,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 35 | \\ _ = comptime {} | 66 | \\ _ = comptime {} |
| 36 | \\ var bad = {}; | 67 | \\ var bad = {}; |
| 37 | \\} | 68 | \\} |
| 38 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 69 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 39 | 70 | ||
| 40 | cases.add("implicit semicolon - defer", | 71 | cases.add("implicit semicolon - defer", |
| 41 | \\export fn entry() { | 72 | \\export fn entry() { |
| ... | @@ -53,7 +84,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -53,7 +84,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 53 | \\ if(true) ({}) | 84 | \\ if(true) ({}) |
| 54 | \\ var bad = {}; | 85 | \\ var bad = {}; |
| 55 | \\} | 86 | \\} |
| 56 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 87 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 57 | 88 | ||
| 58 | cases.add("implicit semicolon - if expression", | 89 | cases.add("implicit semicolon - if expression", |
| 59 | \\export fn entry() { | 90 | \\export fn entry() { |
| ... | @@ -62,7 +93,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -62,7 +93,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 62 | \\ _ = if(true) {} | 93 | \\ _ = if(true) {} |
| 63 | \\ var bad = {}; | 94 | \\ var bad = {}; |
| 64 | \\} | 95 | \\} |
| 65 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 96 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 66 | 97 | ||
| 67 | cases.add("implicit semicolon - if-else statement", | 98 | cases.add("implicit semicolon - if-else statement", |
| 68 | \\export fn entry() { | 99 | \\export fn entry() { |
| ... | @@ -71,7 +102,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -71,7 +102,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 71 | \\ if(true) ({}) else ({}) | 102 | \\ if(true) ({}) else ({}) |
| 72 | \\ var bad = {}; | 103 | \\ var bad = {}; |
| 73 | \\} | 104 | \\} |
| 74 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 105 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 75 | 106 | ||
| 76 | cases.add("implicit semicolon - if-else expression", | 107 | cases.add("implicit semicolon - if-else expression", |
| 77 | \\export fn entry() { | 108 | \\export fn entry() { |
| ... | @@ -80,7 +111,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -80,7 +111,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 80 | \\ _ = if(true) {} else {} | 111 | \\ _ = if(true) {} else {} |
| 81 | \\ var bad = {}; | 112 | \\ var bad = {}; |
| 82 | \\} | 113 | \\} |
| 83 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 114 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 84 | 115 | ||
| 85 | cases.add("implicit semicolon - if-else-if statement", | 116 | cases.add("implicit semicolon - if-else-if statement", |
| 86 | \\export fn entry() { | 117 | \\export fn entry() { |
| ... | @@ -89,7 +120,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -89,7 +120,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 89 | \\ if(true) ({}) else if(true) ({}) | 120 | \\ if(true) ({}) else if(true) ({}) |
| 90 | \\ var bad = {}; | 121 | \\ var bad = {}; |
| 91 | \\} | 122 | \\} |
| 92 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 123 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 93 | 124 | ||
| 94 | cases.add("implicit semicolon - if-else-if expression", | 125 | cases.add("implicit semicolon - if-else-if expression", |
| 95 | \\export fn entry() { | 126 | \\export fn entry() { |
| ... | @@ -98,7 +129,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -98,7 +129,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 98 | \\ _ = if(true) {} else if(true) {} | 129 | \\ _ = if(true) {} else if(true) {} |
| 99 | \\ var bad = {}; | 130 | \\ var bad = {}; |
| 100 | \\} | 131 | \\} |
| 101 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 132 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 102 | 133 | ||
| 103 | cases.add("implicit semicolon - if-else-if-else statement", | 134 | cases.add("implicit semicolon - if-else-if-else statement", |
| 104 | \\export fn entry() { | 135 | \\export fn entry() { |
| ... | @@ -107,7 +138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -107,7 +138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 107 | \\ if(true) ({}) else if(true) ({}) else ({}) | 138 | \\ if(true) ({}) else if(true) ({}) else ({}) |
| 108 | \\ var bad = {}; | 139 | \\ var bad = {}; |
| 109 | \\} | 140 | \\} |
| 110 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 141 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 111 | 142 | ||
| 112 | cases.add("implicit semicolon - if-else-if-else expression", | 143 | cases.add("implicit semicolon - if-else-if-else expression", |
| 113 | \\export fn entry() { | 144 | \\export fn entry() { |
| ... | @@ -116,7 +147,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -116,7 +147,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 116 | \\ _ = if(true) {} else if(true) {} else {} | 147 | \\ _ = if(true) {} else if(true) {} else {} |
| 117 | \\ var bad = {}; | 148 | \\ var bad = {}; |
| 118 | \\} | 149 | \\} |
| 119 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 150 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 120 | 151 | ||
| 121 | cases.add("implicit semicolon - test statement", | 152 | cases.add("implicit semicolon - test statement", |
| 122 | \\export fn entry() { | 153 | \\export fn entry() { |
| ... | @@ -125,7 +156,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -125,7 +156,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 125 | \\ if (foo()) |_| ({}) | 156 | \\ if (foo()) |_| ({}) |
| 126 | \\ var bad = {}; | 157 | \\ var bad = {}; |
| 127 | \\} | 158 | \\} |
| 128 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 159 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 129 | 160 | ||
| 130 | cases.add("implicit semicolon - test expression", | 161 | cases.add("implicit semicolon - test expression", |
| 131 | \\export fn entry() { | 162 | \\export fn entry() { |
| ... | @@ -134,7 +165,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -134,7 +165,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 134 | \\ _ = if (foo()) |_| {} | 165 | \\ _ = if (foo()) |_| {} |
| 135 | \\ var bad = {}; | 166 | \\ var bad = {}; |
| 136 | \\} | 167 | \\} |
| 137 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 168 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 138 | 169 | ||
| 139 | cases.add("implicit semicolon - while statement", | 170 | cases.add("implicit semicolon - while statement", |
| 140 | \\export fn entry() { | 171 | \\export fn entry() { |
| ... | @@ -143,7 +174,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -143,7 +174,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 143 | \\ while(true) ({}) | 174 | \\ while(true) ({}) |
| 144 | \\ var bad = {}; | 175 | \\ var bad = {}; |
| 145 | \\} | 176 | \\} |
| 146 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 177 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 147 | 178 | ||
| 148 | cases.add("implicit semicolon - while expression", | 179 | cases.add("implicit semicolon - while expression", |
| 149 | \\export fn entry() { | 180 | \\export fn entry() { |
| ... | @@ -152,7 +183,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -152,7 +183,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 152 | \\ _ = while(true) {} | 183 | \\ _ = while(true) {} |
| 153 | \\ var bad = {}; | 184 | \\ var bad = {}; |
| 154 | \\} | 185 | \\} |
| 155 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 186 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 156 | 187 | ||
| 157 | cases.add("implicit semicolon - while-continue statement", | 188 | cases.add("implicit semicolon - while-continue statement", |
| 158 | \\export fn entry() { | 189 | \\export fn entry() { |
| ... | @@ -161,7 +192,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -161,7 +192,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 161 | \\ while(true):({}) ({}) | 192 | \\ while(true):({}) ({}) |
| 162 | \\ var bad = {}; | 193 | \\ var bad = {}; |
| 163 | \\} | 194 | \\} |
| 164 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 195 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 165 | 196 | ||
| 166 | cases.add("implicit semicolon - while-continue expression", | 197 | cases.add("implicit semicolon - while-continue expression", |
| 167 | \\export fn entry() { | 198 | \\export fn entry() { |
| ... | @@ -170,7 +201,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -170,7 +201,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 170 | \\ _ = while(true):({}) {} | 201 | \\ _ = while(true):({}) {} |
| 171 | \\ var bad = {}; | 202 | \\ var bad = {}; |
| 172 | \\} | 203 | \\} |
| 173 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 204 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 174 | 205 | ||
| 175 | cases.add("implicit semicolon - for statement", | 206 | cases.add("implicit semicolon - for statement", |
| 176 | \\export fn entry() { | 207 | \\export fn entry() { |
| ... | @@ -179,7 +210,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -179,7 +210,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 179 | \\ for(foo()) ({}) | 210 | \\ for(foo()) ({}) |
| 180 | \\ var bad = {}; | 211 | \\ var bad = {}; |
| 181 | \\} | 212 | \\} |
| 182 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 213 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 183 | 214 | ||
| 184 | cases.add("implicit semicolon - for expression", | 215 | cases.add("implicit semicolon - for expression", |
| 185 | \\export fn entry() { | 216 | \\export fn entry() { |
| ... | @@ -188,7 +219,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -188,7 +219,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 188 | \\ _ = for(foo()) {} | 219 | \\ _ = for(foo()) {} |
| 189 | \\ var bad = {}; | 220 | \\ var bad = {}; |
| 190 | \\} | 221 | \\} |
| 191 | , ".tmp_source.zig:5:5: error: invalid token: 'var'"); | 222 | , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); |
| 192 | 223 | ||
| 193 | cases.add("multiple function definitions", | 224 | cases.add("multiple function definitions", |
| 194 | \\fn a() {} | 225 | \\fn a() {} |
| ... | @@ -245,12 +276,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -245,12 +276,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 245 | 276 | ||
| 246 | cases.add("undeclared identifier", | 277 | cases.add("undeclared identifier", |
| 247 | \\export fn a() { | 278 | \\export fn a() { |
| 279 | \\ return | ||
| 248 | \\ b + | 280 | \\ b + |
| 249 | \\ c | 281 | \\ c; |
| 250 | \\} | 282 | \\} |
| 251 | , | 283 | , |
| 252 | ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'", | 284 | ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'", |
| 253 | ".tmp_source.zig:3:5: error: use of undeclared identifier 'c'"); | 285 | ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'"); |
| 254 | 286 | ||
| 255 | cases.add("parameter redeclaration", | 287 | cases.add("parameter redeclaration", |
| 256 | \\fn f(a : i32, a : i32) { | 288 | \\fn f(a : i32, a : i32) { |
| ... | @@ -275,9 +307,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -275,9 +307,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 275 | cases.add("variable has wrong type", | 307 | cases.add("variable has wrong type", |
| 276 | \\export fn f() -> i32 { | 308 | \\export fn f() -> i32 { |
| 277 | \\ const a = c"a"; | 309 | \\ const a = c"a"; |
| 278 | \\ a | 310 | \\ return a; |
| 279 | \\} | 311 | \\} |
| 280 | , ".tmp_source.zig:3:5: error: expected type 'i32', found '&const u8'"); | 312 | , ".tmp_source.zig:3:12: error: expected type 'i32', found '&const u8'"); |
| 281 | 313 | ||
| 282 | cases.add("if condition is bool, not int", | 314 | cases.add("if condition is bool, not int", |
| 283 | \\export fn f() { | 315 | \\export fn f() { |
| ... | @@ -362,23 +394,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -362,23 +394,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 362 | 394 | ||
| 363 | cases.add("missing else clause", | 395 | cases.add("missing else clause", |
| 364 | \\fn f(b: bool) { | 396 | \\fn f(b: bool) { |
| 365 | \\ const x : i32 = if (b) { 1 }; | 397 | \\ const x : i32 = if (b) h: { break :h 1; }; |
| 366 | \\ const y = if (b) { i32(1) }; | 398 | \\ const y = if (b) h: { break :h i32(1); }; |
| 367 | \\} | 399 | \\} |
| 368 | \\export fn entry() { f(true); } | 400 | \\export fn entry() { f(true); } |
| 369 | , ".tmp_source.zig:2:30: error: integer value 1 cannot be implicitly casted to type 'void'", | 401 | , ".tmp_source.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'", |
| 370 | ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'"); | 402 | ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'"); |
| 371 | 403 | ||
| 372 | cases.add("direct struct loop", | 404 | cases.add("direct struct loop", |
| 373 | \\const A = struct { a : A, }; | 405 | \\const A = struct { a : A, }; |
| 374 | \\export fn entry() -> usize { @sizeOf(A) } | 406 | \\export fn entry() -> usize { return @sizeOf(A); } |
| 375 | , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); | 407 | , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); |
| 376 | 408 | ||
| 377 | cases.add("indirect struct loop", | 409 | cases.add("indirect struct loop", |
| 378 | \\const A = struct { b : B, }; | 410 | \\const A = struct { b : B, }; |
| 379 | \\const B = struct { c : C, }; | 411 | \\const B = struct { c : C, }; |
| 380 | \\const C = struct { a : A, }; | 412 | \\const C = struct { a : A, }; |
| 381 | \\export fn entry() -> usize { @sizeOf(A) } | 413 | \\export fn entry() -> usize { return @sizeOf(A); } |
| 382 | , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); | 414 | , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); |
| 383 | 415 | ||
| 384 | cases.add("invalid struct field", | 416 | cases.add("invalid struct field", |
| ... | @@ -476,10 +508,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -476,10 +508,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 476 | 508 | ||
| 477 | cases.add("cast unreachable", | 509 | cases.add("cast unreachable", |
| 478 | \\fn f() -> i32 { | 510 | \\fn f() -> i32 { |
| 479 | \\ i32(return 1) | 511 | \\ return i32(return 1); |
| 480 | \\} | 512 | \\} |
| 481 | \\export fn entry() { _ = f(); } | 513 | \\export fn entry() { _ = f(); } |
| 482 | , ".tmp_source.zig:2:8: error: unreachable code"); | 514 | , ".tmp_source.zig:2:15: error: unreachable code"); |
| 483 | 515 | ||
| 484 | cases.add("invalid builtin fn", | 516 | cases.add("invalid builtin fn", |
| 485 | \\fn f() -> @bogus(foo) { | 517 | \\fn f() -> @bogus(foo) { |
| ... | @@ -502,7 +534,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -502,7 +534,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 502 | 534 | ||
| 503 | cases.add("struct init syntax for array", | 535 | cases.add("struct init syntax for array", |
| 504 | \\const foo = []u16{.x = 1024,}; | 536 | \\const foo = []u16{.x = 1024,}; |
| 505 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 537 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 506 | , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax"); | 538 | , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax"); |
| 507 | 539 | ||
| 508 | cases.add("type variables must be constant", | 540 | cases.add("type variables must be constant", |
| ... | @@ -545,7 +577,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -545,7 +577,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 545 | \\ } | 577 | \\ } |
| 546 | \\} | 578 | \\} |
| 547 | \\ | 579 | \\ |
| 548 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 580 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 549 | , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch"); | 581 | , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch"); |
| 550 | 582 | ||
| 551 | cases.add("switch expression - duplicate enumeration prong", | 583 | cases.add("switch expression - duplicate enumeration prong", |
| ... | @@ -565,7 +597,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -565,7 +597,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 565 | \\ } | 597 | \\ } |
| 566 | \\} | 598 | \\} |
| 567 | \\ | 599 | \\ |
| 568 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 600 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 569 | , ".tmp_source.zig:13:15: error: duplicate switch value", | 601 | , ".tmp_source.zig:13:15: error: duplicate switch value", |
| 570 | ".tmp_source.zig:10:15: note: other value is here"); | 602 | ".tmp_source.zig:10:15: note: other value is here"); |
| 571 | 603 | ||
| ... | @@ -587,7 +619,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -587,7 +619,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 587 | \\ } | 619 | \\ } |
| 588 | \\} | 620 | \\} |
| 589 | \\ | 621 | \\ |
| 590 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 622 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 591 | , ".tmp_source.zig:13:15: error: duplicate switch value", | 623 | , ".tmp_source.zig:13:15: error: duplicate switch value", |
| 592 | ".tmp_source.zig:10:15: note: other value is here"); | 624 | ".tmp_source.zig:10:15: note: other value is here"); |
| 593 | 625 | ||
| ... | @@ -610,20 +642,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -610,20 +642,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 610 | \\ 0 => {}, | 642 | \\ 0 => {}, |
| 611 | \\ } | 643 | \\ } |
| 612 | \\} | 644 | \\} |
| 613 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 645 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 614 | , | 646 | , |
| 615 | ".tmp_source.zig:2:5: error: switch must handle all possibilities"); | 647 | ".tmp_source.zig:2:5: error: switch must handle all possibilities"); |
| 616 | 648 | ||
| 617 | cases.add("switch expression - duplicate or overlapping integer value", | 649 | cases.add("switch expression - duplicate or overlapping integer value", |
| 618 | \\fn foo(x: u8) -> u8 { | 650 | \\fn foo(x: u8) -> u8 { |
| 619 | \\ switch (x) { | 651 | \\ return switch (x) { |
| 620 | \\ 0 ... 100 => u8(0), | 652 | \\ 0 ... 100 => u8(0), |
| 621 | \\ 101 ... 200 => 1, | 653 | \\ 101 ... 200 => 1, |
| 622 | \\ 201, 203 ... 207 => 2, | 654 | \\ 201, 203 ... 207 => 2, |
| 623 | \\ 206 ... 255 => 3, | 655 | \\ 206 ... 255 => 3, |
| 624 | \\ } | 656 | \\ }; |
| 625 | \\} | 657 | \\} |
| 626 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 658 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 627 | , | 659 | , |
| 628 | ".tmp_source.zig:6:9: error: duplicate switch value", | 660 | ".tmp_source.zig:6:9: error: duplicate switch value", |
| 629 | ".tmp_source.zig:5:14: note: previous value is here"); | 661 | ".tmp_source.zig:5:14: note: previous value is here"); |
| ... | @@ -635,14 +667,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -635,14 +667,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 635 | \\ } | 667 | \\ } |
| 636 | \\} | 668 | \\} |
| 637 | \\const y: u8 = 100; | 669 | \\const y: u8 = 100; |
| 638 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 670 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 639 | , | 671 | , |
| 640 | ".tmp_source.zig:2:5: error: else prong required when switching on type '&u8'"); | 672 | ".tmp_source.zig:2:5: error: else prong required when switching on type '&u8'"); |
| 641 | 673 | ||
| 642 | cases.add("global variable initializer must be constant expression", | 674 | cases.add("global variable initializer must be constant expression", |
| 643 | \\extern fn foo() -> i32; | 675 | \\extern fn foo() -> i32; |
| 644 | \\const x = foo(); | 676 | \\const x = foo(); |
| 645 | \\export fn entry() -> i32 { x } | 677 | \\export fn entry() -> i32 { return x; } |
| 646 | , ".tmp_source.zig:2:11: error: unable to evaluate constant expression"); | 678 | , ".tmp_source.zig:2:11: error: unable to evaluate constant expression"); |
| 647 | 679 | ||
| 648 | cases.add("array concatenation with wrong type", | 680 | cases.add("array concatenation with wrong type", |
| ... | @@ -650,38 +682,38 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -650,38 +682,38 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 650 | \\const derp = usize(1234); | 682 | \\const derp = usize(1234); |
| 651 | \\const a = derp ++ "foo"; | 683 | \\const a = derp ++ "foo"; |
| 652 | \\ | 684 | \\ |
| 653 | \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } | 685 | \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); } |
| 654 | , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'"); | 686 | , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'"); |
| 655 | 687 | ||
| 656 | cases.add("non compile time array concatenation", | 688 | cases.add("non compile time array concatenation", |
| 657 | \\fn f() -> []u8 { | 689 | \\fn f() -> []u8 { |
| 658 | \\ s ++ "foo" | 690 | \\ return s ++ "foo"; |
| 659 | \\} | 691 | \\} |
| 660 | \\var s: [10]u8 = undefined; | 692 | \\var s: [10]u8 = undefined; |
| 661 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 693 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 662 | , ".tmp_source.zig:2:5: error: unable to evaluate constant expression"); | 694 | , ".tmp_source.zig:2:12: error: unable to evaluate constant expression"); |
| 663 | 695 | ||
| 664 | cases.add("@cImport with bogus include", | 696 | cases.add("@cImport with bogus include", |
| 665 | \\const c = @cImport(@cInclude("bogus.h")); | 697 | \\const c = @cImport(@cInclude("bogus.h")); |
| 666 | \\export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } | 698 | \\export fn entry() -> usize { return @sizeOf(@typeOf(c.bogo)); } |
| 667 | , ".tmp_source.zig:1:11: error: C import failed", | 699 | , ".tmp_source.zig:1:11: error: C import failed", |
| 668 | ".h:1:10: note: 'bogus.h' file not found"); | 700 | ".h:1:10: note: 'bogus.h' file not found"); |
| 669 | 701 | ||
| 670 | cases.add("address of number literal", | 702 | cases.add("address of number literal", |
| 671 | \\const x = 3; | 703 | \\const x = 3; |
| 672 | \\const y = &x; | 704 | \\const y = &x; |
| 673 | \\fn foo() -> &const i32 { y } | 705 | \\fn foo() -> &const i32 { return y; } |
| 674 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 706 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 675 | , ".tmp_source.zig:3:26: error: expected type '&const i32', found '&const (integer literal)'"); | 707 | , ".tmp_source.zig:3:33: error: expected type '&const i32', found '&const (integer literal)'"); |
| 676 | 708 | ||
| 677 | cases.add("integer overflow error", | 709 | cases.add("integer overflow error", |
| 678 | \\const x : u8 = 300; | 710 | \\const x : u8 = 300; |
| 679 | \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } | 711 | \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); } |
| 680 | , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'"); | 712 | , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'"); |
| 681 | 713 | ||
| 682 | cases.add("incompatible number literals", | 714 | cases.add("incompatible number literals", |
| 683 | \\const x = 2 == 2.0; | 715 | \\const x = 2 == 2.0; |
| 684 | \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } | 716 | \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); } |
| 685 | , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'"); | 717 | , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'"); |
| 686 | 718 | ||
| 687 | cases.add("missing function call param", | 719 | cases.add("missing function call param", |
| ... | @@ -707,32 +739,32 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -707,32 +739,32 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 707 | \\ const result = members[index](); | 739 | \\ const result = members[index](); |
| 708 | \\} | 740 | \\} |
| 709 | \\ | 741 | \\ |
| 710 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 742 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 711 | , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0"); | 743 | , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0"); |
| 712 | 744 | ||
| 713 | cases.add("missing function name and param name", | 745 | cases.add("missing function name and param name", |
| 714 | \\fn () {} | 746 | \\fn () {} |
| 715 | \\fn f(i32) {} | 747 | \\fn f(i32) {} |
| 716 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 748 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 717 | , | 749 | , |
| 718 | ".tmp_source.zig:1:1: error: missing function name", | 750 | ".tmp_source.zig:1:1: error: missing function name", |
| 719 | ".tmp_source.zig:2:6: error: missing parameter name"); | 751 | ".tmp_source.zig:2:6: error: missing parameter name"); |
| 720 | 752 | ||
| 721 | cases.add("wrong function type", | 753 | cases.add("wrong function type", |
| 722 | \\const fns = []fn(){ a, b, c }; | 754 | \\const fns = []fn(){ a, b, c }; |
| 723 | \\fn a() -> i32 {0} | 755 | \\fn a() -> i32 {return 0;} |
| 724 | \\fn b() -> i32 {1} | 756 | \\fn b() -> i32 {return 1;} |
| 725 | \\fn c() -> i32 {2} | 757 | \\fn c() -> i32 {return 2;} |
| 726 | \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } | 758 | \\export fn entry() -> usize { return @sizeOf(@typeOf(fns)); } |
| 727 | , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'"); | 759 | , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'"); |
| 728 | 760 | ||
| 729 | cases.add("extern function pointer mismatch", | 761 | cases.add("extern function pointer mismatch", |
| 730 | \\const fns = [](fn(i32)->i32){ a, b, c }; | 762 | \\const fns = [](fn(i32)->i32){ a, b, c }; |
| 731 | \\pub fn a(x: i32) -> i32 {x + 0} | 763 | \\pub fn a(x: i32) -> i32 {return x + 0;} |
| 732 | \\pub fn b(x: i32) -> i32 {x + 1} | 764 | \\pub fn b(x: i32) -> i32 {return x + 1;} |
| 733 | \\export fn c(x: i32) -> i32 {x + 2} | 765 | \\export fn c(x: i32) -> i32 {return x + 2;} |
| 734 | \\ | 766 | \\ |
| 735 | \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } | 767 | \\export fn entry() -> usize { return @sizeOf(@typeOf(fns)); } |
| 736 | , ".tmp_source.zig:1:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'"); | 768 | , ".tmp_source.zig:1:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'"); |
| 737 | 769 | ||
| 738 | 770 | ||
| ... | @@ -740,14 +772,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -740,14 +772,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 740 | \\const x : f64 = 1.0; | 772 | \\const x : f64 = 1.0; |
| 741 | \\const y : f32 = x; | 773 | \\const y : f32 = x; |
| 742 | \\ | 774 | \\ |
| 743 | \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } | 775 | \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); } |
| 744 | , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'"); | 776 | , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'"); |
| 745 | 777 | ||
| 746 | 778 | ||
| 747 | cases.add("colliding invalid top level functions", | 779 | cases.add("colliding invalid top level functions", |
| 748 | \\fn func() -> bogus {} | 780 | \\fn func() -> bogus {} |
| 749 | \\fn func() -> bogus {} | 781 | \\fn func() -> bogus {} |
| 750 | \\export fn entry() -> usize { @sizeOf(@typeOf(func)) } | 782 | \\export fn entry() -> usize { return @sizeOf(@typeOf(func)); } |
| 751 | , | 783 | , |
| 752 | ".tmp_source.zig:2:1: error: redefinition of 'func'", | 784 | ".tmp_source.zig:2:1: error: redefinition of 'func'", |
| 753 | ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'"); | 785 | ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'"); |
| ... | @@ -755,7 +787,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -755,7 +787,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 755 | 787 | ||
| 756 | cases.add("bogus compile var", | 788 | cases.add("bogus compile var", |
| 757 | \\const x = @import("builtin").bogus; | 789 | \\const x = @import("builtin").bogus; |
| 758 | \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } | 790 | \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); } |
| 759 | , ".tmp_source.zig:1:29: error: no member named 'bogus' in '"); | 791 | , ".tmp_source.zig:1:29: error: no member named 'bogus' in '"); |
| 760 | 792 | ||
| 761 | 793 | ||
| ... | @@ -764,11 +796,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -764,11 +796,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 764 | \\ y: [get()]u8, | 796 | \\ y: [get()]u8, |
| 765 | \\}; | 797 | \\}; |
| 766 | \\var global_var: usize = 1; | 798 | \\var global_var: usize = 1; |
| 767 | \\fn get() -> usize { global_var } | 799 | \\fn get() -> usize { return global_var; } |
| 768 | \\ | 800 | \\ |
| 769 | \\export fn entry() -> usize { @sizeOf(@typeOf(Foo)) } | 801 | \\export fn entry() -> usize { return @sizeOf(@typeOf(Foo)); } |
| 770 | , | 802 | , |
| 771 | ".tmp_source.zig:5:21: error: unable to evaluate constant expression", | 803 | ".tmp_source.zig:5:28: error: unable to evaluate constant expression", |
| 772 | ".tmp_source.zig:2:12: note: called from here", | 804 | ".tmp_source.zig:2:12: note: called from here", |
| 773 | ".tmp_source.zig:2:8: note: called from here"); | 805 | ".tmp_source.zig:2:8: note: called from here"); |
| 774 | 806 | ||
| ... | @@ -779,7 +811,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -779,7 +811,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 779 | \\}; | 811 | \\}; |
| 780 | \\const x = Foo {.field = 1} + Foo {.field = 2}; | 812 | \\const x = Foo {.field = 1} + Foo {.field = 2}; |
| 781 | \\ | 813 | \\ |
| 782 | \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } | 814 | \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); } |
| 783 | , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'"); | 815 | , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'"); |
| 784 | 816 | ||
| 785 | 817 | ||
| ... | @@ -789,10 +821,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -789,10 +821,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 789 | \\const int_x = u32(1) / u32(0); | 821 | \\const int_x = u32(1) / u32(0); |
| 790 | \\const float_x = f32(1.0) / f32(0.0); | 822 | \\const float_x = f32(1.0) / f32(0.0); |
| 791 | \\ | 823 | \\ |
| 792 | \\export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } | 824 | \\export fn entry1() -> usize { return @sizeOf(@typeOf(lit_int_x)); } |
| 793 | \\export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } | 825 | \\export fn entry2() -> usize { return @sizeOf(@typeOf(lit_float_x)); } |
| 794 | \\export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } | 826 | \\export fn entry3() -> usize { return @sizeOf(@typeOf(int_x)); } |
| 795 | \\export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } | 827 | \\export fn entry4() -> usize { return @sizeOf(@typeOf(float_x)); } |
| 796 | , | 828 | , |
| 797 | ".tmp_source.zig:1:21: error: division by zero is undefined", | 829 | ".tmp_source.zig:1:21: error: division by zero is undefined", |
| 798 | ".tmp_source.zig:2:25: error: division by zero is undefined", | 830 | ".tmp_source.zig:2:25: error: division by zero is undefined", |
| ... | @@ -804,14 +836,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -804,14 +836,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 804 | \\const foo = "a | 836 | \\const foo = "a |
| 805 | \\b"; | 837 | \\b"; |
| 806 | \\ | 838 | \\ |
| 807 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 839 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 808 | , ".tmp_source.zig:1:13: error: newline not allowed in string literal"); | 840 | , ".tmp_source.zig:1:13: error: newline not allowed in string literal"); |
| 809 | 841 | ||
| 810 | cases.add("invalid comparison for function pointers", | 842 | cases.add("invalid comparison for function pointers", |
| 811 | \\fn foo() {} | 843 | \\fn foo() {} |
| 812 | \\const invalid = foo > foo; | 844 | \\const invalid = foo > foo; |
| 813 | \\ | 845 | \\ |
| 814 | \\export fn entry() -> usize { @sizeOf(@typeOf(invalid)) } | 846 | \\export fn entry() -> usize { return @sizeOf(@typeOf(invalid)); } |
| 815 | , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'"); | 847 | , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'"); |
| 816 | 848 | ||
| 817 | cases.add("generic function instance with non-constant expression", | 849 | cases.add("generic function instance with non-constant expression", |
| ... | @@ -820,33 +852,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -820,33 +852,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 820 | \\ return foo(a, b); | 852 | \\ return foo(a, b); |
| 821 | \\} | 853 | \\} |
| 822 | \\ | 854 | \\ |
| 823 | \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) } | 855 | \\export fn entry() -> usize { return @sizeOf(@typeOf(test1)); } |
| 824 | , ".tmp_source.zig:3:16: error: unable to evaluate constant expression"); | 856 | , ".tmp_source.zig:3:16: error: unable to evaluate constant expression"); |
| 825 | 857 | ||
| 826 | cases.add("goto jumping into block", | ||
| 827 | \\export fn f() { | ||
| 828 | \\ { | ||
| 829 | \\a_label: | ||
| 830 | \\ } | ||
| 831 | \\ goto a_label; | ||
| 832 | \\} | ||
| 833 | , ".tmp_source.zig:5:5: error: no label in scope named 'a_label'"); | ||
| 834 | |||
| 835 | cases.add("goto jumping past a defer", | ||
| 836 | \\fn f(b: bool) { | ||
| 837 | \\ if (b) goto label; | ||
| 838 | \\ defer derp(); | ||
| 839 | \\label: | ||
| 840 | \\} | ||
| 841 | \\fn derp(){} | ||
| 842 | \\ | ||
| 843 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | ||
| 844 | , ".tmp_source.zig:2:12: error: no label in scope named 'label'"); | ||
| 845 | |||
| 846 | cases.add("assign null to non-nullable pointer", | 858 | cases.add("assign null to non-nullable pointer", |
| 847 | \\const a: &u8 = null; | 859 | \\const a: &u8 = null; |
| 848 | \\ | 860 | \\ |
| 849 | \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } | 861 | \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); } |
| 850 | , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'"); | 862 | , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'"); |
| 851 | 863 | ||
| 852 | cases.add("indexing an array of size zero", | 864 | cases.add("indexing an array of size zero", |
| ... | @@ -859,18 +871,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -859,18 +871,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 859 | cases.add("compile time division by zero", | 871 | cases.add("compile time division by zero", |
| 860 | \\const y = foo(0); | 872 | \\const y = foo(0); |
| 861 | \\fn foo(x: u32) -> u32 { | 873 | \\fn foo(x: u32) -> u32 { |
| 862 | \\ 1 / x | 874 | \\ return 1 / x; |
| 863 | \\} | 875 | \\} |
| 864 | \\ | 876 | \\ |
| 865 | \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } | 877 | \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); } |
| 866 | , | 878 | , |
| 867 | ".tmp_source.zig:3:7: error: division by zero is undefined", | 879 | ".tmp_source.zig:3:14: error: division by zero is undefined", |
| 868 | ".tmp_source.zig:1:14: note: called from here"); | 880 | ".tmp_source.zig:1:14: note: called from here"); |
| 869 | 881 | ||
| 870 | cases.add("branch on undefined value", | 882 | cases.add("branch on undefined value", |
| 871 | \\const x = if (undefined) true else false; | 883 | \\const x = if (undefined) true else false; |
| 872 | \\ | 884 | \\ |
| 873 | \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } | 885 | \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); } |
| 874 | , ".tmp_source.zig:1:15: error: use of undefined value"); | 886 | , ".tmp_source.zig:1:15: error: use of undefined value"); |
| 875 | 887 | ||
| 876 | 888 | ||
| ... | @@ -880,7 +892,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -880,7 +892,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 880 | \\ return fibbonaci(x - 1) + fibbonaci(x - 2); | 892 | \\ return fibbonaci(x - 1) + fibbonaci(x - 2); |
| 881 | \\} | 893 | \\} |
| 882 | \\ | 894 | \\ |
| 883 | \\export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } | 895 | \\export fn entry() -> usize { return @sizeOf(@typeOf(seventh_fib_number)); } |
| 884 | , | 896 | , |
| 885 | ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches", | 897 | ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches", |
| 886 | ".tmp_source.zig:3:21: note: called from here"); | 898 | ".tmp_source.zig:3:21: note: called from here"); |
| ... | @@ -888,7 +900,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -888,7 +900,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 888 | cases.add("@embedFile with bogus file", | 900 | cases.add("@embedFile with bogus file", |
| 889 | \\const resource = @embedFile("bogus.txt"); | 901 | \\const resource = @embedFile("bogus.txt"); |
| 890 | \\ | 902 | \\ |
| 891 | \\export fn entry() -> usize { @sizeOf(@typeOf(resource)) } | 903 | \\export fn entry() -> usize { return @sizeOf(@typeOf(resource)); } |
| 892 | , ".tmp_source.zig:1:29: error: unable to find '", "bogus.txt'"); | 904 | , ".tmp_source.zig:1:29: error: unable to find '", "bogus.txt'"); |
| 893 | 905 | ||
| 894 | cases.add("non-const expression in struct literal outside function", | 906 | cases.add("non-const expression in struct literal outside function", |
| ... | @@ -898,7 +910,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -898,7 +910,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 898 | \\const a = Foo {.x = get_it()}; | 910 | \\const a = Foo {.x = get_it()}; |
| 899 | \\extern fn get_it() -> i32; | 911 | \\extern fn get_it() -> i32; |
| 900 | \\ | 912 | \\ |
| 901 | \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } | 913 | \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); } |
| 902 | , ".tmp_source.zig:4:21: error: unable to evaluate constant expression"); | 914 | , ".tmp_source.zig:4:21: error: unable to evaluate constant expression"); |
| 903 | 915 | ||
| 904 | cases.add("non-const expression function call with struct return value outside function", | 916 | cases.add("non-const expression function call with struct return value outside function", |
| ... | @@ -908,11 +920,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -908,11 +920,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 908 | \\const a = get_it(); | 920 | \\const a = get_it(); |
| 909 | \\fn get_it() -> Foo { | 921 | \\fn get_it() -> Foo { |
| 910 | \\ global_side_effect = true; | 922 | \\ global_side_effect = true; |
| 911 | \\ Foo {.x = 13} | 923 | \\ return Foo {.x = 13}; |
| 912 | \\} | 924 | \\} |
| 913 | \\var global_side_effect = false; | 925 | \\var global_side_effect = false; |
| 914 | \\ | 926 | \\ |
| 915 | \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } | 927 | \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); } |
| 916 | , | 928 | , |
| 917 | ".tmp_source.zig:6:24: error: unable to evaluate constant expression", | 929 | ".tmp_source.zig:6:24: error: unable to evaluate constant expression", |
| 918 | ".tmp_source.zig:4:17: note: called from here"); | 930 | ".tmp_source.zig:4:17: note: called from here"); |
| ... | @@ -928,21 +940,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -928,21 +940,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 928 | 940 | ||
| 929 | cases.add("illegal comparison of types", | 941 | cases.add("illegal comparison of types", |
| 930 | \\fn bad_eql_1(a: []u8, b: []u8) -> bool { | 942 | \\fn bad_eql_1(a: []u8, b: []u8) -> bool { |
| 931 | \\ a == b | 943 | \\ return a == b; |
| 932 | \\} | 944 | \\} |
| 933 | \\const EnumWithData = union(enum) { | 945 | \\const EnumWithData = union(enum) { |
| 934 | \\ One: void, | 946 | \\ One: void, |
| 935 | \\ Two: i32, | 947 | \\ Two: i32, |
| 936 | \\}; | 948 | \\}; |
| 937 | \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool { | 949 | \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool { |
| 938 | \\ *a == *b | 950 | \\ return *a == *b; |
| 939 | \\} | 951 | \\} |
| 940 | \\ | 952 | \\ |
| 941 | \\export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } | 953 | \\export fn entry1() -> usize { return @sizeOf(@typeOf(bad_eql_1)); } |
| 942 | \\export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } | 954 | \\export fn entry2() -> usize { return @sizeOf(@typeOf(bad_eql_2)); } |
| 943 | , | 955 | , |
| 944 | ".tmp_source.zig:2:7: error: operator not allowed for type '[]u8'", | 956 | ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'", |
| 945 | ".tmp_source.zig:9:8: error: operator not allowed for type 'EnumWithData'"); | 957 | ".tmp_source.zig:9:15: error: operator not allowed for type 'EnumWithData'"); |
| 946 | 958 | ||
| 947 | cases.add("non-const switch number literal", | 959 | cases.add("non-const switch number literal", |
| 948 | \\export fn foo() { | 960 | \\export fn foo() { |
| ... | @@ -953,7 +965,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -953,7 +965,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 953 | \\ }; | 965 | \\ }; |
| 954 | \\} | 966 | \\} |
| 955 | \\fn bar() -> i32 { | 967 | \\fn bar() -> i32 { |
| 956 | \\ 2 | 968 | \\ return 2; |
| 957 | \\} | 969 | \\} |
| 958 | , ".tmp_source.zig:2:15: error: unable to infer expression type"); | 970 | , ".tmp_source.zig:2:15: error: unable to infer expression type"); |
| 959 | 971 | ||
| ... | @@ -976,56 +988,56 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -976,56 +988,56 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 976 | cases.add("negation overflow in function evaluation", | 988 | cases.add("negation overflow in function evaluation", |
| 977 | \\const y = neg(-128); | 989 | \\const y = neg(-128); |
| 978 | \\fn neg(x: i8) -> i8 { | 990 | \\fn neg(x: i8) -> i8 { |
| 979 | \\ -x | 991 | \\ return -x; |
| 980 | \\} | 992 | \\} |
| 981 | \\ | 993 | \\ |
| 982 | \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } | 994 | \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); } |
| 983 | , | 995 | , |
| 984 | ".tmp_source.zig:3:5: error: negation caused overflow", | 996 | ".tmp_source.zig:3:12: error: negation caused overflow", |
| 985 | ".tmp_source.zig:1:14: note: called from here"); | 997 | ".tmp_source.zig:1:14: note: called from here"); |
| 986 | 998 | ||
| 987 | cases.add("add overflow in function evaluation", | 999 | cases.add("add overflow in function evaluation", |
| 988 | \\const y = add(65530, 10); | 1000 | \\const y = add(65530, 10); |
| 989 | \\fn add(a: u16, b: u16) -> u16 { | 1001 | \\fn add(a: u16, b: u16) -> u16 { |
| 990 | \\ a + b | 1002 | \\ return a + b; |
| 991 | \\} | 1003 | \\} |
| 992 | \\ | 1004 | \\ |
| 993 | \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } | 1005 | \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); } |
| 994 | , | 1006 | , |
| 995 | ".tmp_source.zig:3:7: error: operation caused overflow", | 1007 | ".tmp_source.zig:3:14: error: operation caused overflow", |
| 996 | ".tmp_source.zig:1:14: note: called from here"); | 1008 | ".tmp_source.zig:1:14: note: called from here"); |
| 997 | 1009 | ||
| 998 | 1010 | ||
| 999 | cases.add("sub overflow in function evaluation", | 1011 | cases.add("sub overflow in function evaluation", |
| 1000 | \\const y = sub(10, 20); | 1012 | \\const y = sub(10, 20); |
| 1001 | \\fn sub(a: u16, b: u16) -> u16 { | 1013 | \\fn sub(a: u16, b: u16) -> u16 { |
| 1002 | \\ a - b | 1014 | \\ return a - b; |
| 1003 | \\} | 1015 | \\} |
| 1004 | \\ | 1016 | \\ |
| 1005 | \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } | 1017 | \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); } |
| 1006 | , | 1018 | , |
| 1007 | ".tmp_source.zig:3:7: error: operation caused overflow", | 1019 | ".tmp_source.zig:3:14: error: operation caused overflow", |
| 1008 | ".tmp_source.zig:1:14: note: called from here"); | 1020 | ".tmp_source.zig:1:14: note: called from here"); |
| 1009 | 1021 | ||
| 1010 | cases.add("mul overflow in function evaluation", | 1022 | cases.add("mul overflow in function evaluation", |
| 1011 | \\const y = mul(300, 6000); | 1023 | \\const y = mul(300, 6000); |
| 1012 | \\fn mul(a: u16, b: u16) -> u16 { | 1024 | \\fn mul(a: u16, b: u16) -> u16 { |
| 1013 | \\ a * b | 1025 | \\ return a * b; |
| 1014 | \\} | 1026 | \\} |
| 1015 | \\ | 1027 | \\ |
| 1016 | \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } | 1028 | \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); } |
| 1017 | , | 1029 | , |
| 1018 | ".tmp_source.zig:3:7: error: operation caused overflow", | 1030 | ".tmp_source.zig:3:14: error: operation caused overflow", |
| 1019 | ".tmp_source.zig:1:14: note: called from here"); | 1031 | ".tmp_source.zig:1:14: note: called from here"); |
| 1020 | 1032 | ||
| 1021 | cases.add("truncate sign mismatch", | 1033 | cases.add("truncate sign mismatch", |
| 1022 | \\fn f() -> i8 { | 1034 | \\fn f() -> i8 { |
| 1023 | \\ const x: u32 = 10; | 1035 | \\ const x: u32 = 10; |
| 1024 | \\ @truncate(i8, x) | 1036 | \\ return @truncate(i8, x); |
| 1025 | \\} | 1037 | \\} |
| 1026 | \\ | 1038 | \\ |
| 1027 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 1039 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 1028 | , ".tmp_source.zig:3:19: error: expected signed integer type, found 'u32'"); | 1040 | , ".tmp_source.zig:3:26: error: expected signed integer type, found 'u32'"); |
| 1029 | 1041 | ||
| 1030 | cases.add("%return in function with non error return type", | 1042 | cases.add("%return in function with non error return type", |
| 1031 | \\export fn f() { | 1043 | \\export fn f() { |
| ... | @@ -1056,16 +1068,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1056,16 +1068,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1056 | 1068 | ||
| 1057 | cases.add("export function with comptime parameter", | 1069 | cases.add("export function with comptime parameter", |
| 1058 | \\export fn foo(comptime x: i32, y: i32) -> i32{ | 1070 | \\export fn foo(comptime x: i32, y: i32) -> i32{ |
| 1059 | \\ x + y | 1071 | \\ return x + y; |
| 1060 | \\} | 1072 | \\} |
| 1061 | , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); | 1073 | , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); |
| 1062 | 1074 | ||
| 1063 | cases.add("extern function with comptime parameter", | 1075 | cases.add("extern function with comptime parameter", |
| 1064 | \\extern fn foo(comptime x: i32, y: i32) -> i32; | 1076 | \\extern fn foo(comptime x: i32, y: i32) -> i32; |
| 1065 | \\fn f() -> i32 { | 1077 | \\fn f() -> i32 { |
| 1066 | \\ foo(1, 2) | 1078 | \\ return foo(1, 2); |
| 1067 | \\} | 1079 | \\} |
| 1068 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 1080 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 1069 | , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); | 1081 | , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); |
| 1070 | 1082 | ||
| 1071 | cases.add("convert fixed size array to slice with invalid size", | 1083 | cases.add("convert fixed size array to slice with invalid size", |
| ... | @@ -1079,15 +1091,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1079,15 +1091,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1079 | \\var a: u32 = 0; | 1091 | \\var a: u32 = 0; |
| 1080 | \\pub fn List(comptime T: type) -> type { | 1092 | \\pub fn List(comptime T: type) -> type { |
| 1081 | \\ a += 1; | 1093 | \\ a += 1; |
| 1082 | \\ SmallList(T, 8) | 1094 | \\ return SmallList(T, 8); |
| 1083 | \\} | 1095 | \\} |
| 1084 | \\ | 1096 | \\ |
| 1085 | \\pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type { | 1097 | \\pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type { |
| 1086 | \\ struct { | 1098 | \\ return struct { |
| 1087 | \\ items: []T, | 1099 | \\ items: []T, |
| 1088 | \\ length: usize, | 1100 | \\ length: usize, |
| 1089 | \\ prealloc_items: [STATIC_SIZE]T, | 1101 | \\ prealloc_items: [STATIC_SIZE]T, |
| 1090 | \\ } | 1102 | \\ }; |
| 1091 | \\} | 1103 | \\} |
| 1092 | \\ | 1104 | \\ |
| 1093 | \\export fn function_with_return_type_type() { | 1105 | \\export fn function_with_return_type_type() { |
| ... | @@ -1102,7 +1114,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1102,7 +1114,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1102 | \\fn f(m: []const u8) { | 1114 | \\fn f(m: []const u8) { |
| 1103 | \\ m.copy(u8, self[0..], m); | 1115 | \\ m.copy(u8, self[0..], m); |
| 1104 | \\} | 1116 | \\} |
| 1105 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 1117 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 1106 | , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'"); | 1118 | , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'"); |
| 1107 | 1119 | ||
| 1108 | cases.add("wrong number of arguments for method fn call", | 1120 | cases.add("wrong number of arguments for method fn call", |
| ... | @@ -1113,7 +1125,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1113,7 +1125,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1113 | \\ | 1125 | \\ |
| 1114 | \\ foo.method(1, 2); | 1126 | \\ foo.method(1, 2); |
| 1115 | \\} | 1127 | \\} |
| 1116 | \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } | 1128 | \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); } |
| 1117 | , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3"); | 1129 | , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3"); |
| 1118 | 1130 | ||
| 1119 | cases.add("assign through constant pointer", | 1131 | cases.add("assign through constant pointer", |
| ... | @@ -1138,7 +1150,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1138,7 +1150,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1138 | \\fn foo(blah: []u8) { | 1150 | \\fn foo(blah: []u8) { |
| 1139 | \\ for (blah) { } | 1151 | \\ for (blah) { } |
| 1140 | \\} | 1152 | \\} |
| 1141 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 1153 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 1142 | , ".tmp_source.zig:2:5: error: for loop expression missing element parameter"); | 1154 | , ".tmp_source.zig:2:5: error: for loop expression missing element parameter"); |
| 1143 | 1155 | ||
| 1144 | cases.add("misspelled type with pointer only reference", | 1156 | cases.add("misspelled type with pointer only reference", |
| ... | @@ -1171,7 +1183,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1171,7 +1183,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1171 | \\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} }; | 1183 | \\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} }; |
| 1172 | \\} | 1184 | \\} |
| 1173 | \\ | 1185 | \\ |
| 1174 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 1186 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 1175 | , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'"); | 1187 | , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'"); |
| 1176 | 1188 | ||
| 1177 | cases.add("method call with first arg type primitive", | 1189 | cases.add("method call with first arg type primitive", |
| ... | @@ -1179,9 +1191,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1179,9 +1191,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1179 | \\ x: i32, | 1191 | \\ x: i32, |
| 1180 | \\ | 1192 | \\ |
| 1181 | \\ fn init(x: i32) -> Foo { | 1193 | \\ fn init(x: i32) -> Foo { |
| 1182 | \\ Foo { | 1194 | \\ return Foo { |
| 1183 | \\ .x = x, | 1195 | \\ .x = x, |
| 1184 | \\ } | 1196 | \\ }; |
| 1185 | \\ } | 1197 | \\ } |
| 1186 | \\}; | 1198 | \\}; |
| 1187 | \\ | 1199 | \\ |
| ... | @@ -1198,10 +1210,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1198,10 +1210,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1198 | \\ allocator: &Allocator, | 1210 | \\ allocator: &Allocator, |
| 1199 | \\ | 1211 | \\ |
| 1200 | \\ pub fn init(allocator: &Allocator) -> List { | 1212 | \\ pub fn init(allocator: &Allocator) -> List { |
| 1201 | \\ List { | 1213 | \\ return List { |
| 1202 | \\ .len = 0, | 1214 | \\ .len = 0, |
| 1203 | \\ .allocator = allocator, | 1215 | \\ .allocator = allocator, |
| 1204 | \\ } | 1216 | \\ }; |
| 1205 | \\ } | 1217 | \\ } |
| 1206 | \\}; | 1218 | \\}; |
| 1207 | \\ | 1219 | \\ |
| ... | @@ -1224,10 +1236,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1224,10 +1236,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1224 | \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT; | 1236 | \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT; |
| 1225 | \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1); | 1237 | \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1); |
| 1226 | \\ | 1238 | \\ |
| 1227 | \\export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } | 1239 | \\export fn entry() -> usize { return @sizeOf(@typeOf(block_aligned_stuff)); } |
| 1228 | , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'"); | 1240 | , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'"); |
| 1229 | 1241 | ||
| 1230 | cases.addCase({ | 1242 | cases.addCase(x: { |
| 1231 | const tc = cases.create("multiple files with private function error", | 1243 | const tc = cases.create("multiple files with private function error", |
| 1232 | \\const foo = @import("foo.zig"); | 1244 | \\const foo = @import("foo.zig"); |
| 1233 | \\ | 1245 | \\ |
| ... | @@ -1242,14 +1254,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1242,14 +1254,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1242 | \\fn privateFunction() { } | 1254 | \\fn privateFunction() { } |
| 1243 | ); | 1255 | ); |
| 1244 | 1256 | ||
| 1245 | tc | 1257 | break :x tc; |
| 1246 | }); | 1258 | }); |
| 1247 | 1259 | ||
| 1248 | cases.add("container init with non-type", | 1260 | cases.add("container init with non-type", |
| 1249 | \\const zero: i32 = 0; | 1261 | \\const zero: i32 = 0; |
| 1250 | \\const a = zero{1}; | 1262 | \\const a = zero{1}; |
| 1251 | \\ | 1263 | \\ |
| 1252 | \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } | 1264 | \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); } |
| 1253 | , ".tmp_source.zig:2:11: error: expected type, found 'i32'"); | 1265 | , ".tmp_source.zig:2:11: error: expected type, found 'i32'"); |
| 1254 | 1266 | ||
| 1255 | cases.add("assign to constant field", | 1267 | cases.add("assign to constant field", |
| ... | @@ -1277,22 +1289,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1277,22 +1289,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1277 | \\ return 0; | 1289 | \\ return 0; |
| 1278 | \\} | 1290 | \\} |
| 1279 | \\ | 1291 | \\ |
| 1280 | \\export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } | 1292 | \\export fn entry() -> usize { return @sizeOf(@typeOf(testTrickyDefer)); } |
| 1281 | , ".tmp_source.zig:4:11: error: cannot return from defer expression"); | 1293 | , ".tmp_source.zig:4:11: error: cannot return from defer expression"); |
| 1282 | 1294 | ||
| 1283 | cases.add("attempt to access var args out of bounds", | 1295 | cases.add("attempt to access var args out of bounds", |
| 1284 | \\fn add(args: ...) -> i32 { | 1296 | \\fn add(args: ...) -> i32 { |
| 1285 | \\ args[0] + args[1] | 1297 | \\ return args[0] + args[1]; |
| 1286 | \\} | 1298 | \\} |
| 1287 | \\ | 1299 | \\ |
| 1288 | \\fn foo() -> i32 { | 1300 | \\fn foo() -> i32 { |
| 1289 | \\ add(i32(1234)) | 1301 | \\ return add(i32(1234)); |
| 1290 | \\} | 1302 | \\} |
| 1291 | \\ | 1303 | \\ |
| 1292 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 1304 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 1293 | , | 1305 | , |
| 1294 | ".tmp_source.zig:2:19: error: index 1 outside argument list of size 1", | 1306 | ".tmp_source.zig:2:26: error: index 1 outside argument list of size 1", |
| 1295 | ".tmp_source.zig:6:8: note: called from here"); | 1307 | ".tmp_source.zig:6:15: note: called from here"); |
| 1296 | 1308 | ||
| 1297 | cases.add("pass integer literal to var args", | 1309 | cases.add("pass integer literal to var args", |
| 1298 | \\fn add(args: ...) -> i32 { | 1310 | \\fn add(args: ...) -> i32 { |
| ... | @@ -1304,11 +1316,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1304,11 +1316,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1304 | \\} | 1316 | \\} |
| 1305 | \\ | 1317 | \\ |
| 1306 | \\fn bar() -> i32 { | 1318 | \\fn bar() -> i32 { |
| 1307 | \\ add(1, 2, 3, 4) | 1319 | \\ return add(1, 2, 3, 4); |
| 1308 | \\} | 1320 | \\} |
| 1309 | \\ | 1321 | \\ |
| 1310 | \\export fn entry() -> usize { @sizeOf(@typeOf(bar)) } | 1322 | \\export fn entry() -> usize { return @sizeOf(@typeOf(bar)); } |
| 1311 | , ".tmp_source.zig:10:9: error: parameter of type '(integer literal)' requires comptime"); | 1323 | , ".tmp_source.zig:10:16: error: parameter of type '(integer literal)' requires comptime"); |
| 1312 | 1324 | ||
| 1313 | cases.add("assign too big number to u16", | 1325 | cases.add("assign too big number to u16", |
| 1314 | \\export fn foo() { | 1326 | \\export fn foo() { |
| ... | @@ -1318,12 +1330,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1318,12 +1330,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1318 | 1330 | ||
| 1319 | cases.add("global variable alignment non power of 2", | 1331 | cases.add("global variable alignment non power of 2", |
| 1320 | \\const some_data: [100]u8 align(3) = undefined; | 1332 | \\const some_data: [100]u8 align(3) = undefined; |
| 1321 | \\export fn entry() -> usize { @sizeOf(@typeOf(some_data)) } | 1333 | \\export fn entry() -> usize { return @sizeOf(@typeOf(some_data)); } |
| 1322 | , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2"); | 1334 | , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2"); |
| 1323 | 1335 | ||
| 1324 | cases.add("function alignment non power of 2", | 1336 | cases.add("function alignment non power of 2", |
| 1325 | \\extern fn foo() align(3); | 1337 | \\extern fn foo() align(3); |
| 1326 | \\export fn entry() { foo() } | 1338 | \\export fn entry() { return foo(); } |
| 1327 | , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2"); | 1339 | , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2"); |
| 1328 | 1340 | ||
| 1329 | cases.add("compile log", | 1341 | cases.add("compile log", |
| ... | @@ -1358,7 +1370,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1358,7 +1370,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1358 | \\ return *x; | 1370 | \\ return *x; |
| 1359 | \\} | 1371 | \\} |
| 1360 | \\ | 1372 | \\ |
| 1361 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 1373 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 1362 | , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align(1:3:6) const u3'"); | 1374 | , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align(1:3:6) const u3'"); |
| 1363 | 1375 | ||
| 1364 | cases.add("referring to a struct that is invalid", | 1376 | cases.add("referring to a struct that is invalid", |
| ... | @@ -1394,14 +1406,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1394,14 +1406,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1394 | \\export fn foo() { | 1406 | \\export fn foo() { |
| 1395 | \\ bar(); | 1407 | \\ bar(); |
| 1396 | \\} | 1408 | \\} |
| 1397 | \\fn bar() -> i32 { 0 } | 1409 | \\fn bar() -> i32 { return 0; } |
| 1398 | , ".tmp_source.zig:2:8: error: expression value is ignored"); | 1410 | , ".tmp_source.zig:2:8: error: expression value is ignored"); |
| 1399 | 1411 | ||
| 1400 | cases.add("ignored assert-err-ok return value", | 1412 | cases.add("ignored assert-err-ok return value", |
| 1401 | \\export fn foo() { | 1413 | \\export fn foo() { |
| 1402 | \\ %%bar(); | 1414 | \\ %%bar(); |
| 1403 | \\} | 1415 | \\} |
| 1404 | \\fn bar() -> %i32 { 0 } | 1416 | \\fn bar() -> %i32 { return 0; } |
| 1405 | , ".tmp_source.zig:2:5: error: expression value is ignored"); | 1417 | , ".tmp_source.zig:2:5: error: expression value is ignored"); |
| 1406 | 1418 | ||
| 1407 | cases.add("ignored statement value", | 1419 | cases.add("ignored statement value", |
| ... | @@ -1428,11 +1440,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1428,11 +1440,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1428 | \\} | 1440 | \\} |
| 1429 | , ".tmp_source.zig:2:12: error: expression value is ignored"); | 1441 | , ".tmp_source.zig:2:12: error: expression value is ignored"); |
| 1430 | 1442 | ||
| 1431 | cases.add("ignored defered statement value", | 1443 | cases.add("ignored defered function call", |
| 1432 | \\export fn foo() { | 1444 | \\export fn foo() { |
| 1433 | \\ defer bar(); | 1445 | \\ defer bar(); |
| 1434 | \\} | 1446 | \\} |
| 1435 | \\fn bar() -> %i32 { 0 } | 1447 | \\fn bar() -> %i32 { return 0; } |
| 1436 | , ".tmp_source.zig:2:14: error: expression value is ignored"); | 1448 | , ".tmp_source.zig:2:14: error: expression value is ignored"); |
| 1437 | 1449 | ||
| 1438 | cases.add("dereference an array", | 1450 | cases.add("dereference an array", |
| ... | @@ -1443,7 +1455,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1443,7 +1455,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1443 | \\ return (*out)[0..1]; | 1455 | \\ return (*out)[0..1]; |
| 1444 | \\} | 1456 | \\} |
| 1445 | \\ | 1457 | \\ |
| 1446 | \\export fn entry() -> usize { @sizeOf(@typeOf(pass)) } | 1458 | \\export fn entry() -> usize { return @sizeOf(@typeOf(pass)); } |
| 1447 | , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'"); | 1459 | , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'"); |
| 1448 | 1460 | ||
| 1449 | cases.add("pass const ptr to mutable ptr fn", | 1461 | cases.add("pass const ptr to mutable ptr fn", |
| ... | @@ -1456,10 +1468,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1456,10 +1468,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1456 | \\ return true; | 1468 | \\ return true; |
| 1457 | \\} | 1469 | \\} |
| 1458 | \\ | 1470 | \\ |
| 1459 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 1471 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 1460 | , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'"); | 1472 | , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'"); |
| 1461 | 1473 | ||
| 1462 | cases.addCase({ | 1474 | cases.addCase(x: { |
| 1463 | const tc = cases.create("export collision", | 1475 | const tc = cases.create("export collision", |
| 1464 | \\const foo = @import("foo.zig"); | 1476 | \\const foo = @import("foo.zig"); |
| 1465 | \\ | 1477 | \\ |
| ... | @@ -1468,20 +1480,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1468,20 +1480,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1468 | \\} | 1480 | \\} |
| 1469 | , | 1481 | , |
| 1470 | "foo.zig:1:8: error: exported symbol collision: 'bar'", | 1482 | "foo.zig:1:8: error: exported symbol collision: 'bar'", |
| 1471 | ".tmp_source.zig:3:8: note: other symbol is here"); | 1483 | ".tmp_source.zig:3:8: note: other symbol here"); |
| 1472 | 1484 | ||
| 1473 | tc.addSourceFile("foo.zig", | 1485 | tc.addSourceFile("foo.zig", |
| 1474 | \\export fn bar() {} | 1486 | \\export fn bar() {} |
| 1475 | \\pub const baz = 1234; | 1487 | \\pub const baz = 1234; |
| 1476 | ); | 1488 | ); |
| 1477 | 1489 | ||
| 1478 | tc | 1490 | break :x tc; |
| 1479 | }); | 1491 | }); |
| 1480 | 1492 | ||
| 1481 | cases.add("pass non-copyable type by value to function", | 1493 | cases.add("pass non-copyable type by value to function", |
| 1482 | \\const Point = struct { x: i32, y: i32, }; | 1494 | \\const Point = struct { x: i32, y: i32, }; |
| 1483 | \\fn foo(p: Point) { } | 1495 | \\fn foo(p: Point) { } |
| 1484 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 1496 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 1485 | , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value"); | 1497 | , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value"); |
| 1486 | 1498 | ||
| 1487 | cases.add("implicit cast from array to mutable slice", | 1499 | cases.add("implicit cast from array to mutable slice", |
| ... | @@ -1504,7 +1516,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1504,7 +1516,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1504 | \\fn foo(e: error) -> u2 { | 1516 | \\fn foo(e: error) -> u2 { |
| 1505 | \\ return u2(e); | 1517 | \\ return u2(e); |
| 1506 | \\} | 1518 | \\} |
| 1507 | \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } | 1519 | \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); } |
| 1508 | , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'"); | 1520 | , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'"); |
| 1509 | 1521 | ||
| 1510 | cases.add("asm at compile time", | 1522 | cases.add("asm at compile time", |
| ... | @@ -1611,23 +1623,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1611,23 +1623,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1611 | "error: 'main' is private", | 1623 | "error: 'main' is private", |
| 1612 | ".tmp_source.zig:1:1: note: declared here"); | 1624 | ".tmp_source.zig:1:1: note: declared here"); |
| 1613 | 1625 | ||
| 1614 | cases.add("@setGlobalSection extern variable", | 1626 | cases.add("setting a section on an extern variable", |
| 1615 | \\extern var foo: i32; | 1627 | \\extern var foo: i32 section(".text2"); |
| 1616 | \\comptime { | 1628 | \\export fn entry() -> i32 { |
| 1617 | \\ @setGlobalSection(foo, ".text2"); | 1629 | \\ return foo; |
| 1618 | \\} | 1630 | \\} |
| 1619 | , | 1631 | , |
| 1620 | ".tmp_source.zig:3:5: error: cannot set section of external variable 'foo'", | 1632 | ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'"); |
| 1621 | ".tmp_source.zig:1:8: note: declared here"); | ||
| 1622 | 1633 | ||
| 1623 | cases.add("@setGlobalSection extern fn", | 1634 | cases.add("setting a section on a local variable", |
| 1624 | \\extern fn foo(); | 1635 | \\export fn entry() -> i32 { |
| 1625 | \\comptime { | 1636 | \\ var foo: i32 section(".text2") = 1234; |
| 1626 | \\ @setGlobalSection(foo, ".text2"); | 1637 | \\ return foo; |
| 1627 | \\} | 1638 | \\} |
| 1628 | , | 1639 | , |
| 1629 | ".tmp_source.zig:3:5: error: cannot set section of external function 'foo'", | 1640 | ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'"); |
| 1630 | ".tmp_source.zig:1:8: note: declared here"); | 1641 | |
| 1642 | cases.add("setting a section on an extern fn", | ||
| 1643 | \\extern fn foo() section(".text2"); | ||
| 1644 | \\export fn entry() { | ||
| 1645 | \\ foo(); | ||
| 1646 | \\} | ||
| 1647 | , | ||
| 1648 | ".tmp_source.zig:1:25: error: cannot set section of external function 'foo'"); | ||
| 1631 | 1649 | ||
| 1632 | cases.add("returning address of local variable - simple", | 1650 | cases.add("returning address of local variable - simple", |
| 1633 | \\export fn foo() -> &i32 { | 1651 | \\export fn foo() -> &i32 { |
| ... | @@ -1648,17 +1666,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1648,17 +1666,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1648 | 1666 | ||
| 1649 | cases.add("inner struct member shadowing outer struct member", | 1667 | cases.add("inner struct member shadowing outer struct member", |
| 1650 | \\fn A() -> type { | 1668 | \\fn A() -> type { |
| 1651 | \\ struct { | 1669 | \\ return struct { |
| 1652 | \\ b: B(), | 1670 | \\ b: B(), |
| 1653 | \\ | 1671 | \\ |
| 1654 | \\ const Self = this; | 1672 | \\ const Self = this; |
| 1655 | \\ | 1673 | \\ |
| 1656 | \\ fn B() -> type { | 1674 | \\ fn B() -> type { |
| 1657 | \\ struct { | 1675 | \\ return struct { |
| 1658 | \\ const Self = this; | 1676 | \\ const Self = this; |
| 1659 | \\ } | 1677 | \\ }; |
| 1660 | \\ } | 1678 | \\ } |
| 1661 | \\ } | 1679 | \\ }; |
| 1662 | \\} | 1680 | \\} |
| 1663 | \\comptime { | 1681 | \\comptime { |
| 1664 | \\ assert(A().B().Self != A().Self); | 1682 | \\ assert(A().B().Self != A().Self); |
| ... | @@ -1674,7 +1692,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1674,7 +1692,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1674 | \\export fn foo() { | 1692 | \\export fn foo() { |
| 1675 | \\ while (bar()) {} | 1693 | \\ while (bar()) {} |
| 1676 | \\} | 1694 | \\} |
| 1677 | \\fn bar() -> ?i32 { 1 } | 1695 | \\fn bar() -> ?i32 { return 1; } |
| 1678 | , | 1696 | , |
| 1679 | ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'"); | 1697 | ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'"); |
| 1680 | 1698 | ||
| ... | @@ -1682,7 +1700,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1682,7 +1700,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1682 | \\export fn foo() { | 1700 | \\export fn foo() { |
| 1683 | \\ while (bar()) {} | 1701 | \\ while (bar()) {} |
| 1684 | \\} | 1702 | \\} |
| 1685 | \\fn bar() -> %i32 { 1 } | 1703 | \\fn bar() -> %i32 { return 1; } |
| 1686 | , | 1704 | , |
| 1687 | ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'"); | 1705 | ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'"); |
| 1688 | 1706 | ||
| ... | @@ -1690,7 +1708,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1690,7 +1708,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1690 | \\export fn foo() { | 1708 | \\export fn foo() { |
| 1691 | \\ while (bar()) |x| {} | 1709 | \\ while (bar()) |x| {} |
| 1692 | \\} | 1710 | \\} |
| 1693 | \\fn bar() -> bool { true } | 1711 | \\fn bar() -> bool { return true; } |
| 1694 | , | 1712 | , |
| 1695 | ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'"); | 1713 | ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'"); |
| 1696 | 1714 | ||
| ... | @@ -1698,7 +1716,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1698,7 +1716,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1698 | \\export fn foo() { | 1716 | \\export fn foo() { |
| 1699 | \\ while (bar()) |x| {} | 1717 | \\ while (bar()) |x| {} |
| 1700 | \\} | 1718 | \\} |
| 1701 | \\fn bar() -> %i32 { 1 } | 1719 | \\fn bar() -> %i32 { return 1; } |
| 1702 | , | 1720 | , |
| 1703 | ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'"); | 1721 | ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'"); |
| 1704 | 1722 | ||
| ... | @@ -1706,7 +1724,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1706,7 +1724,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1706 | \\export fn foo() { | 1724 | \\export fn foo() { |
| 1707 | \\ while (bar()) |x| {} else |err| {} | 1725 | \\ while (bar()) |x| {} else |err| {} |
| 1708 | \\} | 1726 | \\} |
| 1709 | \\fn bar() -> bool { true } | 1727 | \\fn bar() -> bool { return true; } |
| 1710 | , | 1728 | , |
| 1711 | ".tmp_source.zig:2:15: error: expected error union type, found 'bool'"); | 1729 | ".tmp_source.zig:2:15: error: expected error union type, found 'bool'"); |
| 1712 | 1730 | ||
| ... | @@ -1714,7 +1732,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1714,7 +1732,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1714 | \\export fn foo() { | 1732 | \\export fn foo() { |
| 1715 | \\ while (bar()) |x| {} else |err| {} | 1733 | \\ while (bar()) |x| {} else |err| {} |
| 1716 | \\} | 1734 | \\} |
| 1717 | \\fn bar() -> ?i32 { 1 } | 1735 | \\fn bar() -> ?i32 { return 1; } |
| 1718 | , | 1736 | , |
| 1719 | ".tmp_source.zig:2:15: error: expected error union type, found '?i32'"); | 1737 | ".tmp_source.zig:2:15: error: expected error union type, found '?i32'"); |
| 1720 | 1738 | ||
| ... | @@ -1745,17 +1763,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1745,17 +1763,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1745 | 1763 | ||
| 1746 | cases.add("signed integer division", | 1764 | cases.add("signed integer division", |
| 1747 | \\export fn foo(a: i32, b: i32) -> i32 { | 1765 | \\export fn foo(a: i32, b: i32) -> i32 { |
| 1748 | \\ a / b | 1766 | \\ return a / b; |
| 1749 | \\} | 1767 | \\} |
| 1750 | , | 1768 | , |
| 1751 | ".tmp_source.zig:2:7: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact"); | 1769 | ".tmp_source.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact"); |
| 1752 | 1770 | ||
| 1753 | cases.add("signed integer remainder division", | 1771 | cases.add("signed integer remainder division", |
| 1754 | \\export fn foo(a: i32, b: i32) -> i32 { | 1772 | \\export fn foo(a: i32, b: i32) -> i32 { |
| 1755 | \\ a % b | 1773 | \\ return a % b; |
| 1756 | \\} | 1774 | \\} |
| 1757 | , | 1775 | , |
| 1758 | ".tmp_source.zig:2:7: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod"); | 1776 | ".tmp_source.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod"); |
| 1759 | 1777 | ||
| 1760 | cases.add("cast negative value to unsigned integer", | 1778 | cases.add("cast negative value to unsigned integer", |
| 1761 | \\comptime { | 1779 | \\comptime { |
| ... | @@ -1838,16 +1856,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1838,16 +1856,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1838 | , | 1856 | , |
| 1839 | ".tmp_source.zig:4:13: error: cannot continue out of defer expression"); | 1857 | ".tmp_source.zig:4:13: error: cannot continue out of defer expression"); |
| 1840 | 1858 | ||
| 1841 | cases.add("cannot goto out of defer expression", | ||
| 1842 | \\export fn foo() { | ||
| 1843 | \\ defer { | ||
| 1844 | \\ goto label; | ||
| 1845 | \\ }; | ||
| 1846 | \\label: | ||
| 1847 | \\} | ||
| 1848 | , | ||
| 1849 | ".tmp_source.zig:3:9: error: cannot goto out of defer expression"); | ||
| 1850 | |||
| 1851 | cases.add("calling a var args function only known at runtime", | 1859 | cases.add("calling a var args function only known at runtime", |
| 1852 | \\var foos = []fn(...) { foo1, foo2 }; | 1860 | \\var foos = []fn(...) { foo1, foo2 }; |
| 1853 | \\ | 1861 | \\ |
| ... | @@ -1915,17 +1923,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1915,17 +1923,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1915 | 1923 | ||
| 1916 | cases.add("explicit cast float literal to integer when there is a fraction component", | 1924 | cases.add("explicit cast float literal to integer when there is a fraction component", |
| 1917 | \\export fn entry() -> i32 { | 1925 | \\export fn entry() -> i32 { |
| 1918 | \\ i32(12.34) | 1926 | \\ return i32(12.34); |
| 1919 | \\} | 1927 | \\} |
| 1920 | , | 1928 | , |
| 1921 | ".tmp_source.zig:2:9: error: fractional component prevents float value 12.340000 from being casted to type 'i32'"); | 1929 | ".tmp_source.zig:2:16: error: fractional component prevents float value 12.340000 from being casted to type 'i32'"); |
| 1922 | 1930 | ||
| 1923 | cases.add("non pointer given to @ptrToInt", | 1931 | cases.add("non pointer given to @ptrToInt", |
| 1924 | \\export fn entry(x: i32) -> usize { | 1932 | \\export fn entry(x: i32) -> usize { |
| 1925 | \\ @ptrToInt(x) | 1933 | \\ return @ptrToInt(x); |
| 1926 | \\} | 1934 | \\} |
| 1927 | , | 1935 | , |
| 1928 | ".tmp_source.zig:2:15: error: expected pointer, found 'i32'"); | 1936 | ".tmp_source.zig:2:22: error: expected pointer, found 'i32'"); |
| 1929 | 1937 | ||
| 1930 | cases.add("@shlExact shifts out 1 bits", | 1938 | cases.add("@shlExact shifts out 1 bits", |
| 1931 | \\comptime { | 1939 | \\comptime { |
| ... | @@ -2021,7 +2029,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2021,7 +2029,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2021 | 2029 | ||
| 2022 | cases.add("@alignCast expects pointer or slice", | 2030 | cases.add("@alignCast expects pointer or slice", |
| 2023 | \\export fn entry() { | 2031 | \\export fn entry() { |
| 2024 | \\ @alignCast(4, u32(3)) | 2032 | \\ @alignCast(4, u32(3)); |
| 2025 | \\} | 2033 | \\} |
| 2026 | , | 2034 | , |
| 2027 | ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'"); | 2035 | ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'"); |
| ... | @@ -2033,7 +2041,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2033,7 +2041,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2033 | \\fn testImplicitlyDecreaseFnAlign(ptr: fn () align(8) -> i32, answer: i32) { | 2041 | \\fn testImplicitlyDecreaseFnAlign(ptr: fn () align(8) -> i32, answer: i32) { |
| 2034 | \\ if (ptr() != answer) unreachable; | 2042 | \\ if (ptr() != answer) unreachable; |
| 2035 | \\} | 2043 | \\} |
| 2036 | \\fn alignedSmall() align(4) -> i32 { 1234 } | 2044 | \\fn alignedSmall() align(4) -> i32 { return 1234; } |
| 2037 | , | 2045 | , |
| 2038 | ".tmp_source.zig:2:35: error: expected type 'fn() align(8) -> i32', found 'fn() align(4) -> i32'"); | 2046 | ".tmp_source.zig:2:35: error: expected type 'fn() align(8) -> i32', found 'fn() align(4) -> i32'"); |
| 2039 | 2047 | ||
| ... | @@ -2120,12 +2128,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2120,12 +2128,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2120 | , | 2128 | , |
| 2121 | ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'"); | 2129 | ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'"); |
| 2122 | 2130 | ||
| 2123 | cases.add("wrong types given to setGlobalLinkage", | 2131 | cases.add("wrong types given to @export", |
| 2124 | \\export fn entry() { | 2132 | \\extern fn entry() { } |
| 2125 | \\ @setGlobalLinkage(entry, u32(1234)); | 2133 | \\comptime { |
| 2134 | \\ @export("entry", entry, u32(1234)); | ||
| 2126 | \\} | 2135 | \\} |
| 2127 | , | 2136 | , |
| 2128 | ".tmp_source.zig:2:33: error: expected type 'GlobalLinkage', found 'u32'"); | 2137 | ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'"); |
| 2129 | 2138 | ||
| 2130 | cases.add("struct with invalid field", | 2139 | cases.add("struct with invalid field", |
| 2131 | \\const std = @import("std"); | 2140 | \\const std = @import("std"); |
| ... | @@ -2198,17 +2207,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2198,17 +2207,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2198 | \\const Mode = @import("builtin").Mode; | 2207 | \\const Mode = @import("builtin").Mode; |
| 2199 | \\ | 2208 | \\ |
| 2200 | \\fn Free(comptime filename: []const u8) -> TestCase { | 2209 | \\fn Free(comptime filename: []const u8) -> TestCase { |
| 2201 | \\ TestCase { | 2210 | \\ return TestCase { |
| 2202 | \\ .filename = filename, | 2211 | \\ .filename = filename, |
| 2203 | \\ .problem_type = ProblemType.Free, | 2212 | \\ .problem_type = ProblemType.Free, |
| 2204 | \\ } | 2213 | \\ }; |
| 2205 | \\} | 2214 | \\} |
| 2206 | \\ | 2215 | \\ |
| 2207 | \\fn LibC(comptime filename: []const u8) -> TestCase { | 2216 | \\fn LibC(comptime filename: []const u8) -> TestCase { |
| 2208 | \\ TestCase { | 2217 | \\ return TestCase { |
| 2209 | \\ .filename = filename, | 2218 | \\ .filename = filename, |
| 2210 | \\ .problem_type = ProblemType.LinkLibC, | 2219 | \\ .problem_type = ProblemType.LinkLibC, |
| 2211 | \\ } | 2220 | \\ }; |
| 2212 | \\} | 2221 | \\} |
| 2213 | \\ | 2222 | \\ |
| 2214 | \\const TestCase = struct { | 2223 | \\const TestCase = struct { |
| ... | @@ -2366,9 +2375,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2366,9 +2375,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2366 | \\pub fn MemoryPool(comptime T: type) -> type { | 2375 | \\pub fn MemoryPool(comptime T: type) -> type { |
| 2367 | \\ const free_list_t = @compileError("aoeu"); | 2376 | \\ const free_list_t = @compileError("aoeu"); |
| 2368 | \\ | 2377 | \\ |
| 2369 | \\ struct { | 2378 | \\ return struct { |
| 2370 | \\ free_list: free_list_t, | 2379 | \\ free_list: free_list_t, |
| 2371 | \\ } | 2380 | \\ }; |
| 2372 | \\} | 2381 | \\} |
| 2373 | \\ | 2382 | \\ |
| 2374 | \\export fn entry() { | 2383 | \\export fn entry() { |
| ... | @@ -2643,7 +2652,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2643,7 +2652,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2643 | \\ C: bool, | 2652 | \\ C: bool, |
| 2644 | \\}; | 2653 | \\}; |
| 2645 | \\export fn entry() { | 2654 | \\export fn entry() { |
| 2646 | \\ var a = Payload { .A = { 1234 } }; | 2655 | \\ var a = Payload { .A = 1234 }; |
| 2647 | \\} | 2656 | \\} |
| 2648 | , | 2657 | , |
| 2649 | ".tmp_source.zig:6:29: error: extern union does not support enum tag type"); | 2658 | ".tmp_source.zig:6:29: error: extern union does not support enum tag type"); |
| ... | @@ -2660,7 +2669,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2660,7 +2669,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2660 | \\ C: bool, | 2669 | \\ C: bool, |
| 2661 | \\}; | 2670 | \\}; |
| 2662 | \\export fn entry() { | 2671 | \\export fn entry() { |
| 2663 | \\ var a = Payload { .A = { 1234 } }; | 2672 | \\ var a = Payload { .A = 1234 }; |
| 2664 | \\} | 2673 | \\} |
| 2665 | , | 2674 | , |
| 2666 | ".tmp_source.zig:6:29: error: packed union does not support enum tag type"); | 2675 | ".tmp_source.zig:6:29: error: packed union does not support enum tag type"); |
| ... | @@ -2672,7 +2681,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2672,7 +2681,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2672 | \\ C: bool, | 2681 | \\ C: bool, |
| 2673 | \\}; | 2682 | \\}; |
| 2674 | \\export fn entry() { | 2683 | \\export fn entry() { |
| 2675 | \\ const a = Payload { .A = { 1234 } }; | 2684 | \\ const a = Payload { .A = 1234 }; |
| 2676 | \\ foo(a); | 2685 | \\ foo(a); |
| 2677 | \\} | 2686 | \\} |
| 2678 | \\fn foo(a: &const Payload) { | 2687 | \\fn foo(a: &const Payload) { |
| ... | @@ -2684,4 +2693,47 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2684,4 +2693,47 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2684 | , | 2693 | , |
| 2685 | ".tmp_source.zig:11:13: error: switch on union which has no attached enum", | 2694 | ".tmp_source.zig:11:13: error: switch on union which has no attached enum", |
| 2686 | ".tmp_source.zig:1:17: note: consider 'union(enum)' here"); | 2695 | ".tmp_source.zig:1:17: note: consider 'union(enum)' here"); |
| 2696 | |||
| 2697 | cases.add("enum in field count range but not matching tag", | ||
| 2698 | \\const Foo = enum(u32) { | ||
| 2699 | \\ A = 10, | ||
| 2700 | \\ B = 11, | ||
| 2701 | \\}; | ||
| 2702 | \\export fn entry() { | ||
| 2703 | \\ var x = Foo(0); | ||
| 2704 | \\} | ||
| 2705 | , | ||
| 2706 | ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0", | ||
| 2707 | ".tmp_source.zig:1:13: note: 'Foo' declared here"); | ||
| 2708 | |||
| 2709 | cases.add("comptime cast enum to union but field has payload", | ||
| 2710 | \\const Letter = enum { A, B, C }; | ||
| 2711 | \\const Value = union(Letter) { | ||
| 2712 | \\ A: i32, | ||
| 2713 | \\ B, | ||
| 2714 | \\ C, | ||
| 2715 | \\}; | ||
| 2716 | \\export fn entry() { | ||
| 2717 | \\ var x: Value = Letter.A; | ||
| 2718 | \\} | ||
| 2719 | , | ||
| 2720 | ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'", | ||
| 2721 | ".tmp_source.zig:3:5: note: field 'A' declared here"); | ||
| 2722 | |||
| 2723 | cases.add("runtime cast to union which has non-void fields", | ||
| 2724 | \\const Letter = enum { A, B, C }; | ||
| 2725 | \\const Value = union(Letter) { | ||
| 2726 | \\ A: i32, | ||
| 2727 | \\ B, | ||
| 2728 | \\ C, | ||
| 2729 | \\}; | ||
| 2730 | \\export fn entry() { | ||
| 2731 | \\ foo(Letter.A); | ||
| 2732 | \\} | ||
| 2733 | \\fn foo(l: Letter) { | ||
| 2734 | \\ var x: Value = l; | ||
| 2735 | \\} | ||
| 2736 | , | ||
| 2737 | ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields", | ||
| 2738 | ".tmp_source.zig:3:5: note: field 'A' has type 'i32'"); | ||
| 2687 | } | 2739 | } |
test/debug_safety.zig+15-15| ... | @@ -19,7 +19,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -19,7 +19,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 19 | \\ baz(bar(a)); | 19 | \\ baz(bar(a)); |
| 20 | \\} | 20 | \\} |
| 21 | \\fn bar(a: []const i32) -> i32 { | 21 | \\fn bar(a: []const i32) -> i32 { |
| 22 | \\ a[4] | 22 | \\ return a[4]; |
| 23 | \\} | 23 | \\} |
| 24 | \\fn baz(a: i32) { } | 24 | \\fn baz(a: i32) { } |
| 25 | ); | 25 | ); |
| ... | @@ -34,7 +34,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -34,7 +34,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 34 | \\ if (x == 0) return error.Whatever; | 34 | \\ if (x == 0) return error.Whatever; |
| 35 | \\} | 35 | \\} |
| 36 | \\fn add(a: u16, b: u16) -> u16 { | 36 | \\fn add(a: u16, b: u16) -> u16 { |
| 37 | \\ a + b | 37 | \\ return a + b; |
| 38 | \\} | 38 | \\} |
| 39 | ); | 39 | ); |
| 40 | 40 | ||
| ... | @@ -48,7 +48,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -48,7 +48,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 48 | \\ if (x == 0) return error.Whatever; | 48 | \\ if (x == 0) return error.Whatever; |
| 49 | \\} | 49 | \\} |
| 50 | \\fn sub(a: u16, b: u16) -> u16 { | 50 | \\fn sub(a: u16, b: u16) -> u16 { |
| 51 | \\ a - b | 51 | \\ return a - b; |
| 52 | \\} | 52 | \\} |
| 53 | ); | 53 | ); |
| 54 | 54 | ||
| ... | @@ -62,7 +62,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -62,7 +62,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 62 | \\ if (x == 0) return error.Whatever; | 62 | \\ if (x == 0) return error.Whatever; |
| 63 | \\} | 63 | \\} |
| 64 | \\fn mul(a: u16, b: u16) -> u16 { | 64 | \\fn mul(a: u16, b: u16) -> u16 { |
| 65 | \\ a * b | 65 | \\ return a * b; |
| 66 | \\} | 66 | \\} |
| 67 | ); | 67 | ); |
| 68 | 68 | ||
| ... | @@ -76,7 +76,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -76,7 +76,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 76 | \\ if (x == 32767) return error.Whatever; | 76 | \\ if (x == 32767) return error.Whatever; |
| 77 | \\} | 77 | \\} |
| 78 | \\fn neg(a: i16) -> i16 { | 78 | \\fn neg(a: i16) -> i16 { |
| 79 | \\ -a | 79 | \\ return -a; |
| 80 | \\} | 80 | \\} |
| 81 | ); | 81 | ); |
| 82 | 82 | ||
| ... | @@ -90,7 +90,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -90,7 +90,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 90 | \\ if (x == 32767) return error.Whatever; | 90 | \\ if (x == 32767) return error.Whatever; |
| 91 | \\} | 91 | \\} |
| 92 | \\fn div(a: i16, b: i16) -> i16 { | 92 | \\fn div(a: i16, b: i16) -> i16 { |
| 93 | \\ @divTrunc(a, b) | 93 | \\ return @divTrunc(a, b); |
| 94 | \\} | 94 | \\} |
| 95 | ); | 95 | ); |
| 96 | 96 | ||
| ... | @@ -104,7 +104,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -104,7 +104,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 104 | \\ if (x == 0) return error.Whatever; | 104 | \\ if (x == 0) return error.Whatever; |
| 105 | \\} | 105 | \\} |
| 106 | \\fn shl(a: i16, b: u4) -> i16 { | 106 | \\fn shl(a: i16, b: u4) -> i16 { |
| 107 | \\ @shlExact(a, b) | 107 | \\ return @shlExact(a, b); |
| 108 | \\} | 108 | \\} |
| 109 | ); | 109 | ); |
| 110 | 110 | ||
| ... | @@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 118 | \\ if (x == 0) return error.Whatever; | 118 | \\ if (x == 0) return error.Whatever; |
| 119 | \\} | 119 | \\} |
| 120 | \\fn shl(a: u16, b: u4) -> u16 { | 120 | \\fn shl(a: u16, b: u4) -> u16 { |
| 121 | \\ @shlExact(a, b) | 121 | \\ return @shlExact(a, b); |
| 122 | \\} | 122 | \\} |
| 123 | ); | 123 | ); |
| 124 | 124 | ||
| ... | @@ -132,7 +132,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -132,7 +132,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 132 | \\ if (x == 0) return error.Whatever; | 132 | \\ if (x == 0) return error.Whatever; |
| 133 | \\} | 133 | \\} |
| 134 | \\fn shr(a: i16, b: u4) -> i16 { | 134 | \\fn shr(a: i16, b: u4) -> i16 { |
| 135 | \\ @shrExact(a, b) | 135 | \\ return @shrExact(a, b); |
| 136 | \\} | 136 | \\} |
| 137 | ); | 137 | ); |
| 138 | 138 | ||
| ... | @@ -146,7 +146,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -146,7 +146,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 146 | \\ if (x == 0) return error.Whatever; | 146 | \\ if (x == 0) return error.Whatever; |
| 147 | \\} | 147 | \\} |
| 148 | \\fn shr(a: u16, b: u4) -> u16 { | 148 | \\fn shr(a: u16, b: u4) -> u16 { |
| 149 | \\ @shrExact(a, b) | 149 | \\ return @shrExact(a, b); |
| 150 | \\} | 150 | \\} |
| 151 | ); | 151 | ); |
| 152 | 152 | ||
| ... | @@ -159,7 +159,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -159,7 +159,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 159 | \\ const x = div0(999, 0); | 159 | \\ const x = div0(999, 0); |
| 160 | \\} | 160 | \\} |
| 161 | \\fn div0(a: i32, b: i32) -> i32 { | 161 | \\fn div0(a: i32, b: i32) -> i32 { |
| 162 | \\ @divTrunc(a, b) | 162 | \\ return @divTrunc(a, b); |
| 163 | \\} | 163 | \\} |
| 164 | ); | 164 | ); |
| 165 | 165 | ||
| ... | @@ -173,7 +173,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -173,7 +173,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 173 | \\ if (x == 0) return error.Whatever; | 173 | \\ if (x == 0) return error.Whatever; |
| 174 | \\} | 174 | \\} |
| 175 | \\fn divExact(a: i32, b: i32) -> i32 { | 175 | \\fn divExact(a: i32, b: i32) -> i32 { |
| 176 | \\ @divExact(a, b) | 176 | \\ return @divExact(a, b); |
| 177 | \\} | 177 | \\} |
| 178 | ); | 178 | ); |
| 179 | 179 | ||
| ... | @@ -187,7 +187,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -187,7 +187,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 187 | \\ if (x.len == 0) return error.Whatever; | 187 | \\ if (x.len == 0) return error.Whatever; |
| 188 | \\} | 188 | \\} |
| 189 | \\fn widenSlice(slice: []align(1) const u8) -> []align(1) const i32 { | 189 | \\fn widenSlice(slice: []align(1) const u8) -> []align(1) const i32 { |
| 190 | \\ ([]align(1) const i32)(slice) | 190 | \\ return ([]align(1) const i32)(slice); |
| 191 | \\} | 191 | \\} |
| 192 | ); | 192 | ); |
| 193 | 193 | ||
| ... | @@ -201,7 +201,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -201,7 +201,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 201 | \\ if (x == 0) return error.Whatever; | 201 | \\ if (x == 0) return error.Whatever; |
| 202 | \\} | 202 | \\} |
| 203 | \\fn shorten_cast(x: i32) -> i8 { | 203 | \\fn shorten_cast(x: i32) -> i8 { |
| 204 | \\ i8(x) | 204 | \\ return i8(x); |
| 205 | \\} | 205 | \\} |
| 206 | ); | 206 | ); |
| 207 | 207 | ||
| ... | @@ -215,7 +215,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -215,7 +215,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 215 | \\ if (x == 0) return error.Whatever; | 215 | \\ if (x == 0) return error.Whatever; |
| 216 | \\} | 216 | \\} |
| 217 | \\fn unsigned_cast(x: i32) -> u32 { | 217 | \\fn unsigned_cast(x: i32) -> u32 { |
| 218 | \\ u32(x) | 218 | \\ return u32(x); |
| 219 | \\} | 219 | \\} |
| 220 | ); | 220 | ); |
| 221 | 221 |
test/standalone/pkg_import/pkg.zig+1-1| ... | @@ -1 +1 @@ | ... | @@ -1 +1 @@ |
| 1 | pub fn add(a: i32, b: i32) -> i32 { a + b } | 1 | pub fn add(a: i32, b: i32) -> i32 { return a + b; } |
test/tests.zig+23-7| ... | @@ -189,6 +189,7 @@ pub const CompareOutputContext = struct { | ... | @@ -189,6 +189,7 @@ pub const CompareOutputContext = struct { |
| 189 | expected_output: []const u8, | 189 | expected_output: []const u8, |
| 190 | link_libc: bool, | 190 | link_libc: bool, |
| 191 | special: Special, | 191 | special: Special, |
| 192 | cli_args: []const []const u8, | ||
| 192 | 193 | ||
| 193 | const SourceFile = struct { | 194 | const SourceFile = struct { |
| 194 | filename: []const u8, | 195 | filename: []const u8, |
| ... | @@ -201,6 +202,10 @@ pub const CompareOutputContext = struct { | ... | @@ -201,6 +202,10 @@ pub const CompareOutputContext = struct { |
| 201 | .source = source, | 202 | .source = source, |
| 202 | }); | 203 | }); |
| 203 | } | 204 | } |
| 205 | |||
| 206 | pub fn setCommandLineArgs(self: &TestCase, args: []const []const u8) { | ||
| 207 | self.cli_args = args; | ||
| 208 | } | ||
| 204 | }; | 209 | }; |
| 205 | 210 | ||
| 206 | const RunCompareOutputStep = struct { | 211 | const RunCompareOutputStep = struct { |
| ... | @@ -210,9 +215,11 @@ pub const CompareOutputContext = struct { | ... | @@ -210,9 +215,11 @@ pub const CompareOutputContext = struct { |
| 210 | name: []const u8, | 215 | name: []const u8, |
| 211 | expected_output: []const u8, | 216 | expected_output: []const u8, |
| 212 | test_index: usize, | 217 | test_index: usize, |
| 218 | cli_args: []const []const u8, | ||
| 213 | 219 | ||
| 214 | pub fn create(context: &CompareOutputContext, exe_path: []const u8, | 220 | pub fn create(context: &CompareOutputContext, exe_path: []const u8, |
| 215 | name: []const u8, expected_output: []const u8) -> &RunCompareOutputStep | 221 | name: []const u8, expected_output: []const u8, |
| 222 | cli_args: []const []const u8) -> &RunCompareOutputStep | ||
| 216 | { | 223 | { |
| 217 | const allocator = context.b.allocator; | 224 | const allocator = context.b.allocator; |
| 218 | const ptr = %%allocator.create(RunCompareOutputStep); | 225 | const ptr = %%allocator.create(RunCompareOutputStep); |
| ... | @@ -223,6 +230,7 @@ pub const CompareOutputContext = struct { | ... | @@ -223,6 +230,7 @@ pub const CompareOutputContext = struct { |
| 223 | .expected_output = expected_output, | 230 | .expected_output = expected_output, |
| 224 | .test_index = context.test_index, | 231 | .test_index = context.test_index, |
| 225 | .step = build.Step.init("RunCompareOutput", allocator, make), | 232 | .step = build.Step.init("RunCompareOutput", allocator, make), |
| 233 | .cli_args = cli_args, | ||
| 226 | }; | 234 | }; |
| 227 | context.test_index += 1; | 235 | context.test_index += 1; |
| 228 | return ptr; | 236 | return ptr; |
| ... | @@ -233,10 +241,17 @@ pub const CompareOutputContext = struct { | ... | @@ -233,10 +241,17 @@ pub const CompareOutputContext = struct { |
| 233 | const b = self.context.b; | 241 | const b = self.context.b; |
| 234 | 242 | ||
| 235 | const full_exe_path = b.pathFromRoot(self.exe_path); | 243 | const full_exe_path = b.pathFromRoot(self.exe_path); |
| 244 | var args = ArrayList([]const u8).init(b.allocator); | ||
| 245 | defer args.deinit(); | ||
| 246 | |||
| 247 | %%args.append(full_exe_path); | ||
| 248 | for (self.cli_args) |arg| { | ||
| 249 | %%args.append(arg); | ||
| 250 | } | ||
| 236 | 251 | ||
| 237 | warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); | 252 | warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); |
| 238 | 253 | ||
| 239 | const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator); | 254 | const child = %%os.ChildProcess.init(args.toSliceConst(), b.allocator); |
| 240 | defer child.deinit(); | 255 | defer child.deinit(); |
| 241 | 256 | ||
| 242 | child.stdin_behavior = StdIo.Ignore; | 257 | child.stdin_behavior = StdIo.Ignore; |
| ... | @@ -269,7 +284,7 @@ pub const CompareOutputContext = struct { | ... | @@ -269,7 +284,7 @@ pub const CompareOutputContext = struct { |
| 269 | warn("Process {} terminated unexpectedly\n", full_exe_path); | 284 | warn("Process {} terminated unexpectedly\n", full_exe_path); |
| 270 | return error.TestFailed; | 285 | return error.TestFailed; |
| 271 | }, | 286 | }, |
| 272 | }; | 287 | } |
| 273 | 288 | ||
| 274 | 289 | ||
| 275 | if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) { | 290 | if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) { |
| ... | @@ -364,6 +379,7 @@ pub const CompareOutputContext = struct { | ... | @@ -364,6 +379,7 @@ pub const CompareOutputContext = struct { |
| 364 | .expected_output = expected_output, | 379 | .expected_output = expected_output, |
| 365 | .link_libc = false, | 380 | .link_libc = false, |
| 366 | .special = special, | 381 | .special = special, |
| 382 | .cli_args = []const []const u8{}, | ||
| 367 | }; | 383 | }; |
| 368 | const root_src_name = if (special == Special.Asm) "source.s" else "source.zig"; | 384 | const root_src_name = if (special == Special.Asm) "source.s" else "source.zig"; |
| 369 | tc.addSourceFile(root_src_name, source); | 385 | tc.addSourceFile(root_src_name, source); |
| ... | @@ -420,7 +436,7 @@ pub const CompareOutputContext = struct { | ... | @@ -420,7 +436,7 @@ pub const CompareOutputContext = struct { |
| 420 | } | 436 | } |
| 421 | 437 | ||
| 422 | const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name, | 438 | const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name, |
| 423 | case.expected_output); | 439 | case.expected_output, case.cli_args); |
| 424 | run_and_cmp_output.step.dependOn(&exe.step); | 440 | run_and_cmp_output.step.dependOn(&exe.step); |
| 425 | 441 | ||
| 426 | self.step.dependOn(&run_and_cmp_output.step); | 442 | self.step.dependOn(&run_and_cmp_output.step); |
| ... | @@ -447,7 +463,7 @@ pub const CompareOutputContext = struct { | ... | @@ -447,7 +463,7 @@ pub const CompareOutputContext = struct { |
| 447 | } | 463 | } |
| 448 | 464 | ||
| 449 | const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), | 465 | const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), |
| 450 | annotated_case_name, case.expected_output); | 466 | annotated_case_name, case.expected_output, case.cli_args); |
| 451 | run_and_cmp_output.step.dependOn(&exe.step); | 467 | run_and_cmp_output.step.dependOn(&exe.step); |
| 452 | 468 | ||
| 453 | self.step.dependOn(&run_and_cmp_output.step); | 469 | self.step.dependOn(&run_and_cmp_output.step); |
| ... | @@ -599,7 +615,7 @@ pub const CompileErrorContext = struct { | ... | @@ -599,7 +615,7 @@ pub const CompileErrorContext = struct { |
| 599 | warn("Process {} terminated unexpectedly\n", b.zig_exe); | 615 | warn("Process {} terminated unexpectedly\n", b.zig_exe); |
| 600 | return error.TestFailed; | 616 | return error.TestFailed; |
| 601 | }, | 617 | }, |
| 602 | }; | 618 | } |
| 603 | 619 | ||
| 604 | 620 | ||
| 605 | const stdout = stdout_buf.toSliceConst(); | 621 | const stdout = stdout_buf.toSliceConst(); |
| ... | @@ -875,7 +891,7 @@ pub const TranslateCContext = struct { | ... | @@ -875,7 +891,7 @@ pub const TranslateCContext = struct { |
| 875 | warn("Compilation terminated unexpectedly\n"); | 891 | warn("Compilation terminated unexpectedly\n"); |
| 876 | return error.TestFailed; | 892 | return error.TestFailed; |
| 877 | }, | 893 | }, |
| 878 | }; | 894 | } |
| 879 | 895 | ||
| 880 | const stdout = stdout_buf.toSliceConst(); | 896 | const stdout = stdout_buf.toSliceConst(); |
| 881 | const stderr = stderr_buf.toSliceConst(); | 897 | const stderr = stderr_buf.toSliceConst(); |
test/translate_c.zig+94-168| ... | @@ -203,13 +203,13 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -203,13 +203,13 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 203 | \\pub extern var fn_ptr: ?extern fn(); | 203 | \\pub extern var fn_ptr: ?extern fn(); |
| 204 | , | 204 | , |
| 205 | \\pub inline fn foo() { | 205 | \\pub inline fn foo() { |
| 206 | \\ (??fn_ptr)() | 206 | \\ return (??fn_ptr)(); |
| 207 | \\} | 207 | \\} |
| 208 | , | 208 | , |
| 209 | \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8; | 209 | \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8; |
| 210 | , | 210 | , |
| 211 | \\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 { | 211 | \\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 { |
| 212 | \\ (??fn_ptr2)(arg0, arg1) | 212 | \\ return (??fn_ptr2)(arg0, arg1); |
| 213 | \\} | 213 | \\} |
| 214 | ); | 214 | ); |
| 215 | 215 | ||
| ... | @@ -325,12 +325,12 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -325,12 +325,12 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 325 | \\ return a; | 325 | \\ return a; |
| 326 | \\} | 326 | \\} |
| 327 | , | 327 | , |
| 328 | \\export fn foo1(_arg_a: c_uint) -> c_uint { | 328 | \\pub export fn foo1(_arg_a: c_uint) -> c_uint { |
| 329 | \\ var a = _arg_a; | 329 | \\ var a = _arg_a; |
| 330 | \\ a +%= 1; | 330 | \\ a +%= 1; |
| 331 | \\ return a; | 331 | \\ return a; |
| 332 | \\} | 332 | \\} |
| 333 | \\export fn foo2(_arg_a: c_int) -> c_int { | 333 | \\pub export fn foo2(_arg_a: c_int) -> c_int { |
| 334 | \\ var a = _arg_a; | 334 | \\ var a = _arg_a; |
| 335 | \\ a += 1; | 335 | \\ a += 1; |
| 336 | \\ return a; | 336 | \\ return a; |
| ... | @@ -346,7 +346,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -346,7 +346,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 346 | \\ return i; | 346 | \\ return i; |
| 347 | \\} | 347 | \\} |
| 348 | , | 348 | , |
| 349 | \\export fn log2(_arg_a: c_uint) -> c_int { | 349 | \\pub export fn log2(_arg_a: c_uint) -> c_int { |
| 350 | \\ var a = _arg_a; | 350 | \\ var a = _arg_a; |
| 351 | \\ var i: c_int = 0; | 351 | \\ var i: c_int = 0; |
| 352 | \\ while (a > c_uint(0)) { | 352 | \\ while (a > c_uint(0)) { |
| ... | @@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 367 | \\ return a; | 367 | \\ return a; |
| 368 | \\} | 368 | \\} |
| 369 | , | 369 | , |
| 370 | \\export fn max(a: c_int, b: c_int) -> c_int { | 370 | \\pub export fn max(a: c_int, b: c_int) -> c_int { |
| 371 | \\ if (a < b) return b; | 371 | \\ if (a < b) return b; |
| 372 | \\ if (a < b) return b else return a; | 372 | \\ if (a < b) return b else return a; |
| 373 | \\} | 373 | \\} |
| ... | @@ -382,7 +382,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -382,7 +382,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 382 | \\ return a; | 382 | \\ return a; |
| 383 | \\} | 383 | \\} |
| 384 | , | 384 | , |
| 385 | \\export fn max(a: c_int, b: c_int) -> c_int { | 385 | \\pub export fn max(a: c_int, b: c_int) -> c_int { |
| 386 | \\ if (a == b) return a; | 386 | \\ if (a == b) return a; |
| 387 | \\ if (a != b) return b; | 387 | \\ if (a != b) return b; |
| 388 | \\ return a; | 388 | \\ return a; |
| ... | @@ -407,7 +407,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -407,7 +407,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 407 | \\ c = a % b; | 407 | \\ c = a % b; |
| 408 | \\} | 408 | \\} |
| 409 | , | 409 | , |
| 410 | \\export fn s(a: c_int, b: c_int) -> c_int { | 410 | \\pub export fn s(a: c_int, b: c_int) -> c_int { |
| 411 | \\ var c: c_int; | 411 | \\ var c: c_int; |
| 412 | \\ c = (a + b); | 412 | \\ c = (a + b); |
| 413 | \\ c = (a - b); | 413 | \\ c = (a - b); |
| ... | @@ -415,7 +415,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -415,7 +415,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 415 | \\ c = @divTrunc(a, b); | 415 | \\ c = @divTrunc(a, b); |
| 416 | \\ c = @rem(a, b); | 416 | \\ c = @rem(a, b); |
| 417 | \\} | 417 | \\} |
| 418 | \\export fn u(a: c_uint, b: c_uint) -> c_uint { | 418 | \\pub export fn u(a: c_uint, b: c_uint) -> c_uint { |
| 419 | \\ var c: c_uint; | 419 | \\ var c: c_uint; |
| 420 | \\ c = (a +% b); | 420 | \\ c = (a +% b); |
| 421 | \\ c = (a -% b); | 421 | \\ c = (a -% b); |
| ... | @@ -430,7 +430,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -430,7 +430,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 430 | \\ return (a & b) ^ (a | b); | 430 | \\ return (a & b) ^ (a | b); |
| 431 | \\} | 431 | \\} |
| 432 | , | 432 | , |
| 433 | \\export fn max(a: c_int, b: c_int) -> c_int { | 433 | \\pub export fn max(a: c_int, b: c_int) -> c_int { |
| 434 | \\ return (a & b) ^ (a | b); | 434 | \\ return (a & b) ^ (a | b); |
| 435 | \\} | 435 | \\} |
| 436 | ); | 436 | ); |
| ... | @@ -444,7 +444,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -444,7 +444,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 444 | \\ return a; | 444 | \\ return a; |
| 445 | \\} | 445 | \\} |
| 446 | , | 446 | , |
| 447 | \\export fn max(a: c_int, b: c_int) -> c_int { | 447 | \\pub export fn max(a: c_int, b: c_int) -> c_int { |
| 448 | \\ if ((a < b) or (a == b)) return b; | 448 | \\ if ((a < b) or (a == b)) return b; |
| 449 | \\ if ((a >= b) and (a == b)) return a; | 449 | \\ if ((a >= b) and (a == b)) return a; |
| 450 | \\ return a; | 450 | \\ return a; |
| ... | @@ -458,7 +458,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -458,7 +458,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 458 | \\ a = tmp; | 458 | \\ a = tmp; |
| 459 | \\} | 459 | \\} |
| 460 | , | 460 | , |
| 461 | \\export fn max(_arg_a: c_int) -> c_int { | 461 | \\pub export fn max(_arg_a: c_int) -> c_int { |
| 462 | \\ var a = _arg_a; | 462 | \\ var a = _arg_a; |
| 463 | \\ var tmp: c_int; | 463 | \\ var tmp: c_int; |
| 464 | \\ tmp = a; | 464 | \\ tmp = a; |
| ... | @@ -472,13 +472,13 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -472,13 +472,13 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 472 | \\ c = b = a; | 472 | \\ c = b = a; |
| 473 | \\} | 473 | \\} |
| 474 | , | 474 | , |
| 475 | \\export fn max(a: c_int) { | 475 | \\pub export fn max(a: c_int) { |
| 476 | \\ var b: c_int; | 476 | \\ var b: c_int; |
| 477 | \\ var c: c_int; | 477 | \\ var c: c_int; |
| 478 | \\ c = { | 478 | \\ c = x: { |
| 479 | \\ const _tmp = a; | 479 | \\ const _tmp = a; |
| 480 | \\ b = _tmp; | 480 | \\ b = _tmp; |
| 481 | \\ _tmp | 481 | \\ break :x _tmp; |
| 482 | \\ }; | 482 | \\ }; |
| 483 | \\} | 483 | \\} |
| 484 | ); | 484 | ); |
| ... | @@ -493,7 +493,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -493,7 +493,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 493 | \\ return i; | 493 | \\ return i; |
| 494 | \\} | 494 | \\} |
| 495 | , | 495 | , |
| 496 | \\export fn log2(_arg_a: u32) -> c_int { | 496 | \\pub export fn log2(_arg_a: u32) -> c_int { |
| 497 | \\ var a = _arg_a; | 497 | \\ var a = _arg_a; |
| 498 | \\ var i: c_int = 0; | 498 | \\ var i: c_int = 0; |
| 499 | \\ while (a > c_uint(0)) { | 499 | \\ while (a > c_uint(0)) { |
| ... | @@ -518,7 +518,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -518,7 +518,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 518 | \\void foo(void) { bar(); } | 518 | \\void foo(void) { bar(); } |
| 519 | , | 519 | , |
| 520 | \\pub fn bar() {} | 520 | \\pub fn bar() {} |
| 521 | \\export fn foo() { | 521 | \\pub export fn foo() { |
| 522 | \\ bar(); | 522 | \\ bar(); |
| 523 | \\} | 523 | \\} |
| 524 | ); | 524 | ); |
| ... | @@ -534,7 +534,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -534,7 +534,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 534 | \\pub const struct_Foo = extern struct { | 534 | \\pub const struct_Foo = extern struct { |
| 535 | \\ field: c_int, | 535 | \\ field: c_int, |
| 536 | \\}; | 536 | \\}; |
| 537 | \\export fn read_field(foo: ?&struct_Foo) -> c_int { | 537 | \\pub export fn read_field(foo: ?&struct_Foo) -> c_int { |
| 538 | \\ return (??foo).field; | 538 | \\ return (??foo).field; |
| 539 | \\} | 539 | \\} |
| 540 | ); | 540 | ); |
| ... | @@ -544,7 +544,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -544,7 +544,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 544 | \\ ;;;;; | 544 | \\ ;;;;; |
| 545 | \\} | 545 | \\} |
| 546 | , | 546 | , |
| 547 | \\export fn foo() {} | 547 | \\pub export fn foo() {} |
| 548 | ); | 548 | ); |
| 549 | 549 | ||
| 550 | cases.add("undefined array global", | 550 | cases.add("undefined array global", |
| ... | @@ -560,7 +560,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -560,7 +560,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 560 | \\} | 560 | \\} |
| 561 | , | 561 | , |
| 562 | \\pub var array: [100]c_int = undefined; | 562 | \\pub var array: [100]c_int = undefined; |
| 563 | \\export fn foo(index: c_int) -> c_int { | 563 | \\pub export fn foo(index: c_int) -> c_int { |
| 564 | \\ return array[index]; | 564 | \\ return array[index]; |
| 565 | \\} | 565 | \\} |
| 566 | ); | 566 | ); |
| ... | @@ -571,7 +571,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -571,7 +571,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 571 | \\ return (int)a; | 571 | \\ return (int)a; |
| 572 | \\} | 572 | \\} |
| 573 | , | 573 | , |
| 574 | \\export fn float_to_int(a: f32) -> c_int { | 574 | \\pub export fn float_to_int(a: f32) -> c_int { |
| 575 | \\ return c_int(a); | 575 | \\ return c_int(a); |
| 576 | \\} | 576 | \\} |
| 577 | ); | 577 | ); |
| ... | @@ -581,7 +581,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -581,7 +581,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 581 | \\ return x; | 581 | \\ return x; |
| 582 | \\} | 582 | \\} |
| 583 | , | 583 | , |
| 584 | \\export fn foo(x: ?&c_ushort) -> ?&c_void { | 584 | \\pub export fn foo(x: ?&c_ushort) -> ?&c_void { |
| 585 | \\ return @ptrCast(?&c_void, x); | 585 | \\ return @ptrCast(?&c_void, x); |
| 586 | \\} | 586 | \\} |
| 587 | ); | 587 | ); |
| ... | @@ -592,7 +592,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -592,7 +592,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 592 | \\ return sizeof(int); | 592 | \\ return sizeof(int); |
| 593 | \\} | 593 | \\} |
| 594 | , | 594 | , |
| 595 | \\export fn size_of() -> usize { | 595 | \\pub export fn size_of() -> usize { |
| 596 | \\ return @sizeOf(c_int); | 596 | \\ return @sizeOf(c_int); |
| 597 | \\} | 597 | \\} |
| 598 | ); | 598 | ); |
| ... | @@ -602,7 +602,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -602,7 +602,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 602 | \\ return 0; | 602 | \\ return 0; |
| 603 | \\} | 603 | \\} |
| 604 | , | 604 | , |
| 605 | \\export fn foo() -> ?&c_int { | 605 | \\pub export fn foo() -> ?&c_int { |
| 606 | \\ return null; | 606 | \\ return null; |
| 607 | \\} | 607 | \\} |
| 608 | ); | 608 | ); |
| ... | @@ -612,10 +612,10 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -612,10 +612,10 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 612 | \\ return 1, 2; | 612 | \\ return 1, 2; |
| 613 | \\} | 613 | \\} |
| 614 | , | 614 | , |
| 615 | \\export fn foo() -> c_int { | 615 | \\pub export fn foo() -> c_int { |
| 616 | \\ return { | 616 | \\ return x: { |
| 617 | \\ _ = 1; | 617 | \\ _ = 1; |
| 618 | \\ 2 | 618 | \\ break :x 2; |
| 619 | \\ }; | 619 | \\ }; |
| 620 | \\} | 620 | \\} |
| 621 | ); | 621 | ); |
| ... | @@ -625,7 +625,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -625,7 +625,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 625 | \\ return (1 << 2) >> 1; | 625 | \\ return (1 << 2) >> 1; |
| 626 | \\} | 626 | \\} |
| 627 | , | 627 | , |
| 628 | \\export fn foo() -> c_int { | 628 | \\pub export fn foo() -> c_int { |
| 629 | \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); | 629 | \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); |
| 630 | \\} | 630 | \\} |
| 631 | ); | 631 | ); |
| ... | @@ -643,47 +643,47 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -643,47 +643,47 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 643 | \\ a <<= (a <<= 1); | 643 | \\ a <<= (a <<= 1); |
| 644 | \\} | 644 | \\} |
| 645 | , | 645 | , |
| 646 | \\export fn foo() { | 646 | \\pub export fn foo() { |
| 647 | \\ var a: c_int = 0; | 647 | \\ var a: c_int = 0; |
| 648 | \\ a += { | 648 | \\ a += x: { |
| 649 | \\ const _ref = &a; | 649 | \\ const _ref = &a; |
| 650 | \\ (*_ref) = ((*_ref) + 1); | 650 | \\ (*_ref) = ((*_ref) + 1); |
| 651 | \\ *_ref | 651 | \\ break :x *_ref; |
| 652 | \\ }; | 652 | \\ }; |
| 653 | \\ a -= { | 653 | \\ a -= x: { |
| 654 | \\ const _ref = &a; | 654 | \\ const _ref = &a; |
| 655 | \\ (*_ref) = ((*_ref) - 1); | 655 | \\ (*_ref) = ((*_ref) - 1); |
| 656 | \\ *_ref | 656 | \\ break :x *_ref; |
| 657 | \\ }; | 657 | \\ }; |
| 658 | \\ a *= { | 658 | \\ a *= x: { |
| 659 | \\ const _ref = &a; | 659 | \\ const _ref = &a; |
| 660 | \\ (*_ref) = ((*_ref) * 1); | 660 | \\ (*_ref) = ((*_ref) * 1); |
| 661 | \\ *_ref | 661 | \\ break :x *_ref; |
| 662 | \\ }; | 662 | \\ }; |
| 663 | \\ a &= { | 663 | \\ a &= x: { |
| 664 | \\ const _ref = &a; | 664 | \\ const _ref = &a; |
| 665 | \\ (*_ref) = ((*_ref) & 1); | 665 | \\ (*_ref) = ((*_ref) & 1); |
| 666 | \\ *_ref | 666 | \\ break :x *_ref; |
| 667 | \\ }; | 667 | \\ }; |
| 668 | \\ a |= { | 668 | \\ a |= x: { |
| 669 | \\ const _ref = &a; | 669 | \\ const _ref = &a; |
| 670 | \\ (*_ref) = ((*_ref) | 1); | 670 | \\ (*_ref) = ((*_ref) | 1); |
| 671 | \\ *_ref | 671 | \\ break :x *_ref; |
| 672 | \\ }; | 672 | \\ }; |
| 673 | \\ a ^= { | 673 | \\ a ^= x: { |
| 674 | \\ const _ref = &a; | 674 | \\ const _ref = &a; |
| 675 | \\ (*_ref) = ((*_ref) ^ 1); | 675 | \\ (*_ref) = ((*_ref) ^ 1); |
| 676 | \\ *_ref | 676 | \\ break :x *_ref; |
| 677 | \\ }; | 677 | \\ }; |
| 678 | \\ a >>= @import("std").math.Log2Int(c_int)({ | 678 | \\ a >>= @import("std").math.Log2Int(c_int)(x: { |
| 679 | \\ const _ref = &a; | 679 | \\ const _ref = &a; |
| 680 | \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_int)(1)); | 680 | \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_int)(1)); |
| 681 | \\ *_ref | 681 | \\ break :x *_ref; |
| 682 | \\ }); | 682 | \\ }); |
| 683 | \\ a <<= @import("std").math.Log2Int(c_int)({ | 683 | \\ a <<= @import("std").math.Log2Int(c_int)(x: { |
| 684 | \\ const _ref = &a; | 684 | \\ const _ref = &a; |
| 685 | \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_int)(1)); | 685 | \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_int)(1)); |
| 686 | \\ *_ref | 686 | \\ break :x *_ref; |
| 687 | \\ }); | 687 | \\ }); |
| 688 | \\} | 688 | \\} |
| 689 | ); | 689 | ); |
| ... | @@ -701,47 +701,47 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -701,47 +701,47 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 701 | \\ a <<= (a <<= 1); | 701 | \\ a <<= (a <<= 1); |
| 702 | \\} | 702 | \\} |
| 703 | , | 703 | , |
| 704 | \\export fn foo() { | 704 | \\pub export fn foo() { |
| 705 | \\ var a: c_uint = c_uint(0); | 705 | \\ var a: c_uint = c_uint(0); |
| 706 | \\ a +%= { | 706 | \\ a +%= x: { |
| 707 | \\ const _ref = &a; | 707 | \\ const _ref = &a; |
| 708 | \\ (*_ref) = ((*_ref) +% c_uint(1)); | 708 | \\ (*_ref) = ((*_ref) +% c_uint(1)); |
| 709 | \\ *_ref | 709 | \\ break :x *_ref; |
| 710 | \\ }; | 710 | \\ }; |
| 711 | \\ a -%= { | 711 | \\ a -%= x: { |
| 712 | \\ const _ref = &a; | 712 | \\ const _ref = &a; |
| 713 | \\ (*_ref) = ((*_ref) -% c_uint(1)); | 713 | \\ (*_ref) = ((*_ref) -% c_uint(1)); |
| 714 | \\ *_ref | 714 | \\ break :x *_ref; |
| 715 | \\ }; | 715 | \\ }; |
| 716 | \\ a *%= { | 716 | \\ a *%= x: { |
| 717 | \\ const _ref = &a; | 717 | \\ const _ref = &a; |
| 718 | \\ (*_ref) = ((*_ref) *% c_uint(1)); | 718 | \\ (*_ref) = ((*_ref) *% c_uint(1)); |
| 719 | \\ *_ref | 719 | \\ break :x *_ref; |
| 720 | \\ }; | 720 | \\ }; |
| 721 | \\ a &= { | 721 | \\ a &= x: { |
| 722 | \\ const _ref = &a; | 722 | \\ const _ref = &a; |
| 723 | \\ (*_ref) = ((*_ref) & c_uint(1)); | 723 | \\ (*_ref) = ((*_ref) & c_uint(1)); |
| 724 | \\ *_ref | 724 | \\ break :x *_ref; |
| 725 | \\ }; | 725 | \\ }; |
| 726 | \\ a |= { | 726 | \\ a |= x: { |
| 727 | \\ const _ref = &a; | 727 | \\ const _ref = &a; |
| 728 | \\ (*_ref) = ((*_ref) | c_uint(1)); | 728 | \\ (*_ref) = ((*_ref) | c_uint(1)); |
| 729 | \\ *_ref | 729 | \\ break :x *_ref; |
| 730 | \\ }; | 730 | \\ }; |
| 731 | \\ a ^= { | 731 | \\ a ^= x: { |
| 732 | \\ const _ref = &a; | 732 | \\ const _ref = &a; |
| 733 | \\ (*_ref) = ((*_ref) ^ c_uint(1)); | 733 | \\ (*_ref) = ((*_ref) ^ c_uint(1)); |
| 734 | \\ *_ref | 734 | \\ break :x *_ref; |
| 735 | \\ }; | 735 | \\ }; |
| 736 | \\ a >>= @import("std").math.Log2Int(c_uint)({ | 736 | \\ a >>= @import("std").math.Log2Int(c_uint)(x: { |
| 737 | \\ const _ref = &a; | 737 | \\ const _ref = &a; |
| 738 | \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_uint)(1)); | 738 | \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_uint)(1)); |
| 739 | \\ *_ref | 739 | \\ break :x *_ref; |
| 740 | \\ }); | 740 | \\ }); |
| 741 | \\ a <<= @import("std").math.Log2Int(c_uint)({ | 741 | \\ a <<= @import("std").math.Log2Int(c_uint)(x: { |
| 742 | \\ const _ref = &a; | 742 | \\ const _ref = &a; |
| 743 | \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_uint)(1)); | 743 | \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_uint)(1)); |
| 744 | \\ *_ref | 744 | \\ break :x *_ref; |
| 745 | \\ }); | 745 | \\ }); |
| 746 | \\} | 746 | \\} |
| 747 | ); | 747 | ); |
| ... | @@ -771,36 +771,36 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -771,36 +771,36 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 771 | \\ u = u--; | 771 | \\ u = u--; |
| 772 | \\} | 772 | \\} |
| 773 | , | 773 | , |
| 774 | \\export fn foo() { | 774 | \\pub export fn foo() { |
| 775 | \\ var i: c_int = 0; | 775 | \\ var i: c_int = 0; |
| 776 | \\ var u: c_uint = c_uint(0); | 776 | \\ var u: c_uint = c_uint(0); |
| 777 | \\ i += 1; | 777 | \\ i += 1; |
| 778 | \\ i -= 1; | 778 | \\ i -= 1; |
| 779 | \\ u +%= 1; | 779 | \\ u +%= 1; |
| 780 | \\ u -%= 1; | 780 | \\ u -%= 1; |
| 781 | \\ i = { | 781 | \\ i = x: { |
| 782 | \\ const _ref = &i; | 782 | \\ const _ref = &i; |
| 783 | \\ const _tmp = *_ref; | 783 | \\ const _tmp = *_ref; |
| 784 | \\ (*_ref) += 1; | 784 | \\ (*_ref) += 1; |
| 785 | \\ _tmp | 785 | \\ break :x _tmp; |
| 786 | \\ }; | 786 | \\ }; |
| 787 | \\ i = { | 787 | \\ i = x: { |
| 788 | \\ const _ref = &i; | 788 | \\ const _ref = &i; |
| 789 | \\ const _tmp = *_ref; | 789 | \\ const _tmp = *_ref; |
| 790 | \\ (*_ref) -= 1; | 790 | \\ (*_ref) -= 1; |
| 791 | \\ _tmp | 791 | \\ break :x _tmp; |
| 792 | \\ }; | 792 | \\ }; |
| 793 | \\ u = { | 793 | \\ u = x: { |
| 794 | \\ const _ref = &u; | 794 | \\ const _ref = &u; |
| 795 | \\ const _tmp = *_ref; | 795 | \\ const _tmp = *_ref; |
| 796 | \\ (*_ref) +%= 1; | 796 | \\ (*_ref) +%= 1; |
| 797 | \\ _tmp | 797 | \\ break :x _tmp; |
| 798 | \\ }; | 798 | \\ }; |
| 799 | \\ u = { | 799 | \\ u = x: { |
| 800 | \\ const _ref = &u; | 800 | \\ const _ref = &u; |
| 801 | \\ const _tmp = *_ref; | 801 | \\ const _tmp = *_ref; |
| 802 | \\ (*_ref) -%= 1; | 802 | \\ (*_ref) -%= 1; |
| 803 | \\ _tmp | 803 | \\ break :x _tmp; |
| 804 | \\ }; | 804 | \\ }; |
| 805 | \\} | 805 | \\} |
| 806 | ); | 806 | ); |
| ... | @@ -819,32 +819,32 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -819,32 +819,32 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 819 | \\ u = --u; | 819 | \\ u = --u; |
| 820 | \\} | 820 | \\} |
| 821 | , | 821 | , |
| 822 | \\export fn foo() { | 822 | \\pub export fn foo() { |
| 823 | \\ var i: c_int = 0; | 823 | \\ var i: c_int = 0; |
| 824 | \\ var u: c_uint = c_uint(0); | 824 | \\ var u: c_uint = c_uint(0); |
| 825 | \\ i += 1; | 825 | \\ i += 1; |
| 826 | \\ i -= 1; | 826 | \\ i -= 1; |
| 827 | \\ u +%= 1; | 827 | \\ u +%= 1; |
| 828 | \\ u -%= 1; | 828 | \\ u -%= 1; |
| 829 | \\ i = { | 829 | \\ i = x: { |
| 830 | \\ const _ref = &i; | 830 | \\ const _ref = &i; |
| 831 | \\ (*_ref) += 1; | 831 | \\ (*_ref) += 1; |
| 832 | \\ *_ref | 832 | \\ break :x *_ref; |
| 833 | \\ }; | 833 | \\ }; |
| 834 | \\ i = { | 834 | \\ i = x: { |
| 835 | \\ const _ref = &i; | 835 | \\ const _ref = &i; |
| 836 | \\ (*_ref) -= 1; | 836 | \\ (*_ref) -= 1; |
| 837 | \\ *_ref | 837 | \\ break :x *_ref; |
| 838 | \\ }; | 838 | \\ }; |
| 839 | \\ u = { | 839 | \\ u = x: { |
| 840 | \\ const _ref = &u; | 840 | \\ const _ref = &u; |
| 841 | \\ (*_ref) +%= 1; | 841 | \\ (*_ref) +%= 1; |
| 842 | \\ *_ref | 842 | \\ break :x *_ref; |
| 843 | \\ }; | 843 | \\ }; |
| 844 | \\ u = { | 844 | \\ u = x: { |
| 845 | \\ const _ref = &u; | 845 | \\ const _ref = &u; |
| 846 | \\ (*_ref) -%= 1; | 846 | \\ (*_ref) -%= 1; |
| 847 | \\ *_ref | 847 | \\ break :x *_ref; |
| 848 | \\ }; | 848 | \\ }; |
| 849 | \\} | 849 | \\} |
| 850 | ); | 850 | ); |
| ... | @@ -862,7 +862,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -862,7 +862,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 862 | \\ while (b != 0); | 862 | \\ while (b != 0); |
| 863 | \\} | 863 | \\} |
| 864 | , | 864 | , |
| 865 | \\export fn foo() { | 865 | \\pub export fn foo() { |
| 866 | \\ var a: c_int = 2; | 866 | \\ var a: c_int = 2; |
| 867 | \\ while (true) { | 867 | \\ while (true) { |
| 868 | \\ a -= 1; | 868 | \\ a -= 1; |
| ... | @@ -886,9 +886,9 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -886,9 +886,9 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 886 | \\ baz(); | 886 | \\ baz(); |
| 887 | \\} | 887 | \\} |
| 888 | , | 888 | , |
| 889 | \\export fn foo() {} | 889 | \\pub export fn foo() {} |
| 890 | \\export fn baz() {} | 890 | \\pub export fn baz() {} |
| 891 | \\export fn bar() { | 891 | \\pub export fn bar() { |
| 892 | \\ var f: ?extern fn() = foo; | 892 | \\ var f: ?extern fn() = foo; |
| 893 | \\ (??f)(); | 893 | \\ (??f)(); |
| 894 | \\ (??f)(); | 894 | \\ (??f)(); |
| ... | @@ -901,8 +901,8 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -901,8 +901,8 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 901 | \\ *x = 1; | 901 | \\ *x = 1; |
| 902 | \\} | 902 | \\} |
| 903 | , | 903 | , |
| 904 | \\export fn foo(x: ?&c_int) { | 904 | \\pub export fn foo(x: ?&c_int) { |
| 905 | \\ (*(??x)) = 1; | 905 | \\ (*??x) = 1; |
| 906 | \\} | 906 | \\} |
| 907 | ); | 907 | ); |
| 908 | 908 | ||
| ... | @@ -930,7 +930,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -930,7 +930,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 930 | \\pub fn foo() -> c_int { | 930 | \\pub fn foo() -> c_int { |
| 931 | \\ var x: c_int = 1234; | 931 | \\ var x: c_int = 1234; |
| 932 | \\ var ptr: ?&c_int = &x; | 932 | \\ var ptr: ?&c_int = &x; |
| 933 | \\ return *(??ptr); | 933 | \\ return *??ptr; |
| 934 | \\} | 934 | \\} |
| 935 | ); | 935 | ); |
| 936 | 936 | ||
| ... | @@ -1005,48 +1005,6 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -1005,48 +1005,6 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 1005 | \\} | 1005 | \\} |
| 1006 | ); | 1006 | ); |
| 1007 | 1007 | ||
| 1008 | cases.add("switch statement", | ||
| 1009 | \\int foo(int x) { | ||
| 1010 | \\ switch (x) { | ||
| 1011 | \\ case 1: | ||
| 1012 | \\ x += 1; | ||
| 1013 | \\ case 2: | ||
| 1014 | \\ break; | ||
| 1015 | \\ case 3: | ||
| 1016 | \\ case 4: | ||
| 1017 | \\ return x + 1; | ||
| 1018 | \\ default: | ||
| 1019 | \\ return 10; | ||
| 1020 | \\ } | ||
| 1021 | \\ return x + 13; | ||
| 1022 | \\} | ||
| 1023 | , | ||
| 1024 | \\fn foo(_arg_x: c_int) -> c_int { | ||
| 1025 | \\ var x = _arg_x; | ||
| 1026 | \\ { | ||
| 1027 | \\ switch (x) { | ||
| 1028 | \\ 1 => goto case_0, | ||
| 1029 | \\ 2 => goto case_1, | ||
| 1030 | \\ 3 => goto case_2, | ||
| 1031 | \\ 4 => goto case_3, | ||
| 1032 | \\ else => goto default, | ||
| 1033 | \\ }; | ||
| 1034 | \\ case_0: | ||
| 1035 | \\ x += 1; | ||
| 1036 | \\ case_1: | ||
| 1037 | \\ goto end; | ||
| 1038 | \\ case_2: | ||
| 1039 | \\ case_3: | ||
| 1040 | \\ return x + 1; | ||
| 1041 | \\ default: | ||
| 1042 | \\ return 10; | ||
| 1043 | \\ goto end; | ||
| 1044 | \\ end: | ||
| 1045 | \\ }; | ||
| 1046 | \\ return x + 13; | ||
| 1047 | \\} | ||
| 1048 | ); | ||
| 1049 | |||
| 1050 | cases.add("macros with field targets", | 1008 | cases.add("macros with field targets", |
| 1051 | \\typedef unsigned int GLbitfield; | 1009 | \\typedef unsigned int GLbitfield; |
| 1052 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); | 1010 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); |
| ... | @@ -1079,50 +1037,12 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -1079,50 +1037,12 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 1079 | \\pub const glClearPFN = PFNGLCLEARPROC; | 1037 | \\pub const glClearPFN = PFNGLCLEARPROC; |
| 1080 | , | 1038 | , |
| 1081 | \\pub inline fn glClearUnion(arg0: GLbitfield) { | 1039 | \\pub inline fn glClearUnion(arg0: GLbitfield) { |
| 1082 | \\ (??glProcs.gl.Clear)(arg0) | 1040 | \\ return (??glProcs.gl.Clear)(arg0); |
| 1083 | \\} | 1041 | \\} |
| 1084 | , | 1042 | , |
| 1085 | \\pub const OpenGLProcs = union_OpenGLProcs; | 1043 | \\pub const OpenGLProcs = union_OpenGLProcs; |
| 1086 | ); | 1044 | ); |
| 1087 | 1045 | ||
| 1088 | cases.add("switch statement with no default", | ||
| 1089 | \\int foo(int x) { | ||
| 1090 | \\ switch (x) { | ||
| 1091 | \\ case 1: | ||
| 1092 | \\ x += 1; | ||
| 1093 | \\ case 2: | ||
| 1094 | \\ break; | ||
| 1095 | \\ case 3: | ||
| 1096 | \\ case 4: | ||
| 1097 | \\ return x + 1; | ||
| 1098 | \\ } | ||
| 1099 | \\ return x + 13; | ||
| 1100 | \\} | ||
| 1101 | , | ||
| 1102 | \\fn foo(_arg_x: c_int) -> c_int { | ||
| 1103 | \\ var x = _arg_x; | ||
| 1104 | \\ { | ||
| 1105 | \\ switch (x) { | ||
| 1106 | \\ 1 => goto case_0, | ||
| 1107 | \\ 2 => goto case_1, | ||
| 1108 | \\ 3 => goto case_2, | ||
| 1109 | \\ 4 => goto case_3, | ||
| 1110 | \\ else => goto end, | ||
| 1111 | \\ }; | ||
| 1112 | \\ case_0: | ||
| 1113 | \\ x += 1; | ||
| 1114 | \\ case_1: | ||
| 1115 | \\ goto end; | ||
| 1116 | \\ case_2: | ||
| 1117 | \\ case_3: | ||
| 1118 | \\ return x + 1; | ||
| 1119 | \\ goto end; | ||
| 1120 | \\ end: | ||
| 1121 | \\ }; | ||
| 1122 | \\ return x + 13; | ||
| 1123 | \\} | ||
| 1124 | ); | ||
| 1125 | |||
| 1126 | cases.add("variable name shadowing", | 1046 | cases.add("variable name shadowing", |
| 1127 | \\int foo(void) { | 1047 | \\int foo(void) { |
| 1128 | \\ int x = 1; | 1048 | \\ int x = 1; |
| ... | @@ -1188,4 +1108,10 @@ pub fn addCases(cases: &tests.TranslateCContext) { | ... | @@ -1188,4 +1108,10 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 1188 | \\ const v2: &const u8 = c"2.2.2"; | 1108 | \\ const v2: &const u8 = c"2.2.2"; |
| 1189 | \\} | 1109 | \\} |
| 1190 | ); | 1110 | ); |
| 1111 | |||
| 1112 | cases.add("macro pointer cast", | ||
| 1113 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) | ||
| 1114 | , | ||
| 1115 | \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast(&NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr(&NRF_GPIO_Type, NRF_GPIO_BASE) else (&NRF_GPIO_Type)(NRF_GPIO_BASE); | ||
| 1116 | ); | ||
| 1191 | } | 1117 | } |