authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-23 12:00:25-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-23 12:00:25-05:00
logfe660462837231353b846bf398637ca84f67bfc9
tree37336cfcf44810d73d111a57207b843a01fd205f
parentfe39ca01bcbee0077b21d5ddc2776df974e8c6d3
parent39c7bd24e4f768b23074b8634ac637b175b7639f

Merge remote-tracking branch 'origin/master' into llvm6


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[![Build Status](https://travis-ci.org/zig-lang/zig.svg?branch=master)](https://travis-ci.org/zig-lang/zig)119[![Build Status](https://travis-ci.org/zig-lang/zig.svg?branch=master)](https://travis-ci.org/zig-lang/zig)
120[![Build status](https://ci.appveyor.com/api/projects/status/4t80mk2dmucrc38i/branch/master?svg=true)](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master)120[![Build status](https://ci.appveyor.com/api/projects/status/4t80mk2dmucrc38i/branch/master?svg=true)](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master)
121121
122### Dependencies122### Stage 1: Build Zig from C++ Source Code
123123
124#### Build Dependencies124#### Dependencies
125
126These compile tools must be available on your system and are used to build
127the Zig compiler itself:
128125
129##### POSIX126##### POSIX
130127
131 * gcc >= 5.0.0 or clang >= 3.6.0128 * gcc >= 5.0.0 or clang >= 3.6.0
132 * cmake >= 2.8.5129 * cmake >= 2.8.5
130 * LLVM, Clang, LLD libraries == 6.x, compiled with the same gcc or clang version above
133131
134##### Windows132##### Windows
135133
136 * Microsoft Visual Studio 2015134 * Microsoft Visual Studio 2015
135 * LLVM, Clang, LLD libraries == 6.x, compiled with the same MSVC version above
137136
138#### Library Dependencies137#### Instructions
139
140These libraries must be installed on your system, with the development files
141available. The Zig compiler links against them. You have to use the same
142compiler for these libraries as you do to compile Zig.
143
144 * LLVM, Clang, and LLD libraries == 6.x
145
146### Debug / Development Build
147138
148If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`,139If 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 to140`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 test149./zig build --build-file ../build.zig test
159```150```
160151
161#### MacOS152##### MacOS
162153
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.
164155
...@@ -172,21 +163,35 @@ make install...@@ -172,21 +163,35 @@ make install
172./zig build --build-file ../build.zig test163./zig build --build-file ../build.zig test
173```164```
174165
175#### Windows166##### Windows
176167
177See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows168See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows
178169
179### Release / Install Build170### Stage 2: Build Self-Hosted Zig from Zig Source Code
180171
181Once installed, `ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_INCLUDE_DIR` can be overridden172*Note: Stage 2 compiler is not complete. Beta users of Zig should use the
182by the `--libc-lib-dir` and `--libc-include-dir` parameters to the zig binary.173Stage 1 compiler for now.*
174
175Dependencies are the same as Stage 1, except now you have a working zig compiler.
183176
184```177```
185mkdir build178bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install
186cd build179```
187cmake .. -DCMAKE_BUILD_TYPE=Release -DZIG_LIBC_LIB_DIR=/some/path -DZIG_LIBC_INCLUDE_DIR=/some/path -DZIG_LIBC_STATIC_INCLUDE_DIR=/some/path180
188make181### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler
189sudo make install182
183This 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```
191196
192### Test Coverage197### Test Coverage
build.zig+218-8
...@@ -1,6 +1,13 @@...@@ -1,6 +1,13 @@
1const Builder = @import("std").build.Builder;1const std = @import("std");
2const Builder = std.build.Builder;
2const tests = @import("test/tests.zig");3const tests = @import("test/tests.zig");
3const os = @import("std").os;4const os = std.os;
5const BufMap = std.BufMap;
6const warn = std.debug.warn;
7const mem = std.mem;
8const ArrayList = std.ArrayList;
9const Buffer = std.Buffer;
10const io = std.io;
411
5pub fn build(b: &Builder) {12pub 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);
2734
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);
3140
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);
3443
35 b.installArtifact(exe);44 b.installArtifact(exe);
45 installStdLib(b);
46 }
3647
3748
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));
5566
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
79fn 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
91const LibraryDep = struct {
92 libdirs: ArrayList([]const u8),
93 libs: ArrayList([]const u8),
94 includes: ArrayList([]const u8),
95};
96
97fn 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
151pub 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 {
4242
43// TODO look for code segments43// TODO look for code segments
4444
45fn gen(in: &io.InStream, out: &const io.OutStream) {45fn 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;
30213022
3022// Functions are declared like this3023// Functions are declared like this
3023// The last expression in the function can be used as the return value.
3024fn add(a: i8, b: i8) -&gt; i8 {3024fn 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 }
30293029
3030 a + b3030 return a + b;
3031}3031}
30323032
3033// The export specifier makes a function externally visible in the generated3033// 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
58155820
5816TestDecl = "test" String Block5821TestDecl = "test" String Block
58175822
5818TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl)5823TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
58195824
5820ErrorValueDecl = "error" Symbol ";"5825ErrorValueDecl = "error" Symbol ";"
58215826
5822GlobalVarDecl = VariableDeclaration ";"5827GlobalVarDecl = option("export") VariableDeclaration ";"
5828
5829LocalVarDecl = option("comptime") VariableDeclaration
58235830
5824VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression5831VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression
58255832
5826ContainerMember = (ContainerField | FnDef | GlobalVarDecl)5833ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
58275834
...@@ -5831,21 +5838,17 @@ UseDecl = "use" Expression ";"...@@ -5831,21 +5838,17 @@ UseDecl = "use" Expression ";"
58315838
5832ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"5839ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
58335840
5834FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("-&gt;" TypeExpr)5841FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("-&gt;" TypeExpr)
58355842
5836VisibleMod = "pub" | "export"5843FnDef = option("inline" | "export") FnProto Block
5837
5838FnDef = option("inline" | "extern") FnProto Block
58395844
5840ParamDeclList = "(" list(ParamDecl, ",") ")"5845ParamDeclList = "(" list(ParamDecl, ",") ")"
58415846
5842ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")5847ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
58435848
5844Block = "{" many(Statement) option(Expression) "}"5849Block = option(Symbol ":") "{" many(Statement) "}"
5845
5846Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
58475850
5848Label = Symbol ":"5851Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
58495852
5850TypeExpr = PrefixOpExpression | "var"5853TypeExpr = PrefixOpExpression | "var"
58515854
...@@ -5885,13 +5888,13 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=&gt;" option("|" option("*") Sy...@@ -5885,13 +5888,13 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=&gt;" option("|" option("*") Sy
58855888
5886SwitchItem = Expression | (Expression "..." Expression)5889SwitchItem = Expression | (Expression "..." Expression)
58875890
5888ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body))5891ForExpression(body) = option(Symbol ":") option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body))
58895892
5890BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression5893BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
58915894
5892ReturnExpression = option("%") "return" option(Expression)5895ReturnExpression = option("%") "return" option(Expression)
58935896
5894BreakExpression = "break" option(Expression)5897BreakExpression = "break" option(":" Symbol) option(Expression)
58955898
5896Defer(body) = option("%") "defer" body5899Defer(body) = option("%") "defer" body
58975900
...@@ -5901,7 +5904,7 @@ TryExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|")...@@ -5901,7 +5904,7 @@ TryExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|")
59015904
5902TestExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body option("else" BlockExpression(body))5905TestExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body option("else" BlockExpression(body))
59035906
5904WhileExpression(body) = option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body))5907WhileExpression(body) = option(Symbol ":") option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body))
59055908
5906BoolAndExpression = ComparisonExpression "and" BoolAndExpression | ComparisonExpression5909BoolAndExpression = ComparisonExpression "and" BoolAndExpression | ComparisonExpression
59075910
...@@ -5949,15 +5952,13 @@ StructLiteralField = "." Symbol "=" Expression...@@ -5949,15 +5952,13 @@ StructLiteralField = "." Symbol "=" Expression
59495952
5950PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"5953PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
59515954
5952PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl5955PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol))
59535956
5954ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr5957ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
59555958
5956GotoExpression = "goto" Symbol
5957
5958GroupedExpression = "(" Expression ")"5959GroupedExpression = "(" Expression ")"
59595960
5960KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"5961KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
59615962
5962ContainerDecl = option("extern" | "packed")5963ContainerDecl = 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 @@
1export fn add(a: i32, b: i32) -> i32 {1export fn add(a: i32, b: i32) -> i32 {
2 a + b2 return a + b;
3}3}
src-self-hosted/ast.zig created+273
...@@ -0,0 +1,273 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const ArrayList = std.ArrayList;
4const Token = @import("tokenizer.zig").Token;
5const mem = std.mem;
6
7pub 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
54pub 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
66pub 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
101pub 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
110pub 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
155pub 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
173pub 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
189pub 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
219pub 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
257pub 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
266pub 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 @@
1pub 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 @@
1const builtin = @import("builtin");
2const c = @import("c.zig");
3const assert = @import("std").debug.assert;
4
5pub const ValueRef = removeNullability(c.LLVMValueRef);
6pub const ModuleRef = removeNullability(c.LLVMModuleRef);
7pub const ContextRef = removeNullability(c.LLVMContextRef);
8pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
9
10fn 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 @@
1const std = @import("std");
2const mem = std.mem;
3const io = std.io;
4const os = std.os;
5const heap = std.heap;
6const warn = std.debug.warn;
7const assert = std.debug.assert;
8const target = @import("target.zig");
9const Target = target.Target;
10const Module = @import("module.zig").Module;
11const ErrColor = Module.ErrColor;
12const Emit = Module.Emit;
1const builtin = @import("builtin");13const builtin = @import("builtin");
2const io = @import("std").io;14const ArrayList = std.ArrayList;
3const os = @import("std").os;
4const heap = @import("std").heap;
515
6// TODO: sync up CLI with c++ code16error InvalidCommandLineArguments;
7// TODO: concurrency17error ZigLibDirNotFound;
18error ZigInstallationNotFound;
819
9error InvalidArgument;20const default_zig_cache_name = "zig-cache";
10error MissingArg0;
11
12var arg0: []u8 = undefined;
13
14var stderr_file: io.File = undefined;
15const stderr = &stderr_file.out_stream;
1621
17pub fn main() -> %void {22pub 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}
3130
32pub fn internal_main() -> %void {31const Cmd = enum {
33 var args_it = os.args();32 None,
33 Build,
34 Test,
35 Version,
36 Zen,
37 TranslateC,
38 Targets,
39};
3440
35 var incrementing_allocator = heap.IncrementingAllocator.init(10 * 1024 * 1024) %% |err| {41fn 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
50pub fn main2() -> %void {
51 const allocator = std.heap.c_allocator;
52
53 const args = %return os.argsAlloc(allocator);
54 defer os.argsFree(allocator, args);
4055
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;
4561
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();
54102
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();
57105
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-path168 // 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")) {
154217 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}
202469
203fn printUsage(outstream: &io.OutStream) -> %void {470fn 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.zig475 \\ build build project from build.zig
208 \\ build-exe [source] create executable from source or object files476 \\ 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 build485 \\ --assembly [source] add assembly file to build
218 \\ --cache-dir [path] override the cache directory486 \\ --cache-dir [path] override the cache directory
219 \\ --color [auto|off|on] enable or disable colored error messages487 \\ --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 diagnostics489 \\ --enable-timing-info print timing diagnostics
221 \\ --libc-include-dir [path] directory where libc stdlib.h resides490 \\ --libc-include-dir [path] directory where libc stdlib.h resides
222 \\ --name [name] override output name491 \\ --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 architecture500 \\ --target-arch [name] specify target architecture
232 \\ --target-environ [name] specify target environment501 \\ --target-environ [name] specify target environment
233 \\ --target-os [name] specify target operating system502 \\ --target-os [name] specify target operating system
234 \\ --verbose turn on compiler debug output503 \\ --verbose-tokenize enable compiler debug info: tokenization
235 \\ --verbose-link turn on compiler debug output for linking only504 \\ --verbose-ast-tree enable compiler debug info: parsing into an AST (treeview)
236 \\ --verbose-ir turn on compiler debug output for IR only505 \\ --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 installed510 \\ --zig-install-prefix [path] override directory where zig thinks it is installed
238 \\ -dirafter [dir] same as -isystem but do it last511 \\ -dirafter [dir] same as -isystem but do it last
239 \\ -isystem [dir] add additional search path for other .h files512 \\ -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 path528 \\ -rpath [path] add directory to the runtime library search path
256 \\ -mconsole (windows) --subsystem console to the linker529 \\ -mconsole (windows) --subsystem console to the linker
257 \\ -mwindows (windows) --subsystem windows to the linker530 \\ -mwindows (windows) --subsystem windows to the linker
258 \\ -municode (windows) link with unicode
259 \\ -framework [name] (darwin) link against framework531 \\ -framework [name] (darwin) link against framework
260 \\ -mios-version-min [ver] (darwin) set iOS deployment target532 \\ -mios-version-min [ver] (darwin) set iOS deployment target
261 \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target533 \\ -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}
273545
274const ZIG_ZEN =546fn 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
567fn 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
583fn 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
597fn 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 @@
1const std = @import("std");
2const os = std.os;
3const io = std.io;
4const mem = std.mem;
5const Buffer = std.Buffer;
6const llvm = @import("llvm.zig");
7const c = @import("c.zig");
8const builtin = @import("builtin");
9const Target = @import("target.zig").Target;
10const warn = std.debug.warn;
11const Tokenizer = @import("tokenizer.zig").Tokenizer;
12const Token = @import("tokenizer.zig").Token;
13const Parser = @import("parser.zig").Parser;
14const ArrayList = std.ArrayList;
15
16pub 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
290fn 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 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const ArrayList = std.ArrayList;
4const mem = std.mem;
5const ast = @import("ast.zig");
6const Tokenizer = @import("tokenizer.zig").Tokenizer;
7const Token = @import("tokenizer.zig").Token;
8const builtin = @import("builtin");
9const io = std.io;
10
11// TODO when we make parse errors into error types instead of printing directly,
12// get rid of this
13const warn = std.debug.warn;
14
15error ParseError;
16
17pub 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
1086var fixed_buffer_mem: [100 * 1024]u8 = undefined;
1087
1088fn 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
1104fn 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
1136test "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 @@
1const builtin = @import("builtin");
2const c = @import("c.zig");
3
4pub const CrossTarget = struct {
5 arch: builtin.Arch,
6 os: builtin.Os,
7 environ: builtin.Environ,
8};
9
10pub 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
54pub 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 @@
1const std = @import("std");
2const mem = std.mem;
3
4pub 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
139pub 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;
26struct TypeTableEntry;26struct TypeTableEntry;
27struct VariableTableEntry;27struct VariableTableEntry;
28struct ErrorTableEntry;28struct ErrorTableEntry;
29struct LabelTableEntry;
30struct BuiltinFnEntry;29struct BuiltinFnEntry;
31struct TypeStructField;30struct TypeStructField;
32struct CodeGen;31struct CodeGen;
...@@ -37,6 +36,7 @@ struct IrBasicBlock;...@@ -37,6 +36,7 @@ struct IrBasicBlock;
37struct ScopeDecls;36struct ScopeDecls;
38struct ZigWindowsSDK;37struct ZigWindowsSDK;
39struct Tld;38struct Tld;
39struct TldExport;
4040
41struct IrGotoItem {41struct 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 {
272enum VisibMod {271enum VisibMod {
273 VisibModPrivate,272 VisibModPrivate,
274 VisibModPub,273 VisibModPub,
275 VisibModExport,
276};274};
277275
278enum GlobalLinkageId {276enum GlobalLinkageId {
...@@ -313,11 +311,8 @@ struct TldVar {...@@ -313,11 +311,8 @@ struct TldVar {
313 Tld base;311 Tld base;
314312
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};
322317
323struct TldFn {318struct 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 present427 // 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};
436432
437struct AstNodeFnDef {433struct AstNodeFnDef {
...@@ -452,8 +448,8 @@ struct AstNodeParamDecl {...@@ -452,8 +448,8 @@ struct AstNodeParamDecl {
452};448};
453449
454struct AstNodeBlock {450struct AstNodeBlock {
451 Buf *name;
455 ZigList<AstNode *> statements;452 ZigList<AstNode *> statements;
456 bool last_statement_is_result_expression;
457};453};
458454
459enum ReturnKind {455enum 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 null482 // 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 declaration485 // populated if this is an extern declaration
489 Buf *lib_name;486 Buf *lib_name;
490 // populated if the "align A" is present487 // 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};
493492
494struct AstNodeErrorValueDecl {493struct AstNodeErrorValueDecl {
...@@ -659,6 +658,7 @@ struct AstNodeTestExpr {...@@ -659,6 +658,7 @@ struct AstNodeTestExpr {
659};658};
660659
661struct AstNodeWhileExpr {660struct 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};
671671
672struct AstNodeForExpr {672struct AstNodeForExpr {
673 Buf *name;
673 AstNode *array_expr;674 AstNode *array_expr;
674 AstNode *elem_node; // always a symbol675 AstNode *elem_node; // always a symbol
675 AstNode *index_node; // always a symbol, might be null676 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};
703704
704struct AstNodeGoto {
705 Buf *name;
706 bool is_inline;
707};
708
709struct AstNodeCompTime {705struct AstNodeCompTime {
710 AstNode *expr;706 AstNode *expr;
711};707};
...@@ -833,11 +829,14 @@ struct AstNodeBoolLiteral {...@@ -833,11 +829,14 @@ struct AstNodeBoolLiteral {
833};829};
834830
835struct AstNodeBreakExpr {831struct AstNodeBreakExpr {
832 Buf *name;
836 AstNode *expr; // may be null833 AstNode *expr; // may be null
837};834};
838835
839struct AstNodeContinueExpr {836struct AstNodeContinueExpr {
837 Buf *name;
840};838};
839
841struct AstNodeUnreachableExpr {840struct AstNodeUnreachableExpr {
842};841};
843842
...@@ -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};
11791177
1178struct FnExport {
1179 Buf name;
1180 GlobalLinkageId linkage;
1181};
1182
1180struct FnTableEntry {1183struct 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;
12061209
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};
12141216
1215uint32_t fn_table_entry_hash(FnTableEntry*);1217uint32_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};
12821284
1283struct BuiltinFnEntry {1285struct 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;
14291431
14301432
...@@ -1439,7 +1441,7 @@ struct CodeGen {...@@ -1439,7 +1441,7 @@ struct CodeGen {
14391441
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};
16411643
1642struct LabelTableEntry {
1643 AstNode *decl_node;
1644 IrBasicBlock *bb;
1645 bool used;
1646};
1647
1648enum ScopeId {1644enum ScopeId {
1649 ScopeIdDecls,1645 ScopeIdDecls,
1650 ScopeIdBlock,1646 ScopeIdBlock,
...@@ -1688,7 +1684,12 @@ struct ScopeDecls {...@@ -1688,7 +1684,12 @@ struct ScopeDecls {
1688struct ScopeBlock {1684struct ScopeBlock {
1689 Scope base;1685 Scope base;
16901686
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 {
1734struct ScopeLoop {1735struct ScopeLoop {
1735 Scope base;1736 Scope base;
17361737
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};
19041905
1905struct IrInstruction {1906struct 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};
21072108
2108struct IrInstructionConst {2109struct IrInstructionConst {
...@@ -2625,20 +2626,6 @@ struct IrInstructionCanImplicitCast {...@@ -2625,20 +2626,6 @@ struct IrInstructionCanImplicitCast {
2625 IrInstruction *target_value;2626 IrInstruction *target_value;
2626};2627};
26272628
2628struct IrInstructionSetGlobalSection {
2629 IrInstruction base;
2630
2631 Tld *tld;
2632 IrInstruction *value;
2633};
2634
2635struct IrInstructionSetGlobalLinkage {
2636 IrInstruction base;
2637
2638 Tld *tld;
2639 IrInstruction *value;
2640};
2641
2642struct IrInstructionDeclRef {2629struct IrInstructionDeclRef {
2643 IrInstruction base;2630 IrInstruction base;
26442631
...@@ -2727,6 +2714,14 @@ struct IrInstructionArgType {...@@ -2727,6 +2714,14 @@ struct IrInstructionArgType {
2727 IrInstruction *arg_index;2714 IrInstruction *arg_index;
2728};2715};
27292716
2717struct IrInstructionExport {
2718 IrInstruction base;
2719
2720 IrInstruction *name;
2721 IrInstruction *linkage;
2722 IrInstruction *target;
2723};
2724
2730static const size_t slice_ptr_index = 0;2725static const size_t slice_ptr_index = 0;
2731static const size_t slice_len_index = 1;2726static const size_t slice_len_index = 1;
27322727
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}
116116
...@@ -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}
145145
146ScopeLoop *create_loop_scope(AstNode *node, Scope *parent) {146ScopeLoop *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}
152158
...@@ -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);
430436
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);
435441
...@@ -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;
10631069
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}
10951101
1102static 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
1096static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) {1134static 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 }
11311169
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 }
11331180
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) {
22272274
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}
24762521
2477FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) {2522FnTableEntry *create_fn_raw(FnInline inline_value) {
2478 FnTableEntry *fn_entry = allocate<FnTableEntry>(1);2523 FnTableEntry *fn_entry = allocate<FnTableEntry>(1);
24792524
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;
24862530
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;
24932537
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);
24982540
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}
25522594
2595void 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
2553static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {2623static 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, '_');
25632633
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;
25652640
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 }
25802655
...@@ -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) {
25822657
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);
25842659
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;
25992683 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);
26192700
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, '_');
26212702
...@@ -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}
26432724
2644static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {2725static 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);
26482736
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 }
26582745
...@@ -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}
27332820
2734
2735void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node,2821void 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;
29883072
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;
29923076
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 }
29983082
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 }
30023084
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 }
30113093
3012
3013 IrInstruction *init_value = nullptr;3094 IrInstruction *init_value = nullptr;
30143095
3015 // TODO more validation for types that can't be used for export/extern variables3096 // 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 }
30603141
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}
30633153
...@@ -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) {
33193409
3320TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {3410TypeUnionField *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) {
33313421
3332TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {3422TypeUnionField *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;
37273817
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);
37293821
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 }
37623833
...@@ -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) {
5438bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {5518bool 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);
180180
181uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry);181uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry);
182TypeTableEntry *get_align_amt_type(CodeGen *g);182TypeTableEntry *get_align_amt_type(CodeGen *g);
183PackageTableEntry *new_anonymous_package(void);
184
185Buf *const_value_to_buffer(ConstExprValue *const_val);
186void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc);
183187
184#endif188#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}
114113
114static 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 }
443452
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));
586601
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 }
618636
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};
2629
27enum CNumLitSuffix {30enum 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}
5757
58PackageTableEntry *new_anonymous_package(void) {
59 return new_package("", "");
60}
61
58CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,62CodeGen *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}
389393
394static 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
390static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {408static 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;
393411
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 }
396426
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 mangling431 // 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 }
403434
404435
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);
419456
...@@ -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 }
443480
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 }
459486
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}
845873
...@@ -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) {
988static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {1016static 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}
9941022
...@@ -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 }
12121240
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, "");
12141244
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);
12191249
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);
21722202
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, "");
21752207
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;
21792211
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 }
23182350
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 }
23212363
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, "");
23252367
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}
26852727
2686static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRef *instruction) {2728static 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
29783032
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
37503804
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);
39514020
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) {
39604029
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);
39664036
...@@ -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 Int5026 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}
49845055
4985static const char *bool_to_str(bool b) {5056static 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) {
52985369
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 }
53055372
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}
53145386
5315static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) {5387static 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);
54195491
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 }
54435522
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);
56685747
5669 if (fn_table_entry->linkage == GlobalLinkageIdInternal)5748 if (fn_table_entry->export_list.length == 0)
5670 continue;5749 continue;
56715750
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}
209209
210static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) {
211 return IrInstructionIdExport;
212}
213
210static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) {214static 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}
525529
526static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection *) {
527 return IrInstructionIdSetGlobalSection;
528}
529
530static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalLinkage *) {
531 return IrInstructionIdSetGlobalLinkage;
532}
533
534static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) {530static 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
928924
929static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,925static 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;
940936
...@@ -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
948944
949static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,945static 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;
10271023
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);
10301026
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);
11931189
1190 var->decl_instruction = &decl_var_instruction->base;
1191
1194 return &decl_var_instruction->base;1192 return &decl_var_instruction->base;
1195}1193}
11961194
...@@ -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}
12051203
1204static 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
1206static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) {1222static 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}
21592175
2160static 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
2173static 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
2186static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node,2176static 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}
23962386
2387static 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
2397static IrInstruction *ir_instruction_loadptr_get_dep(IrInstructionLoadPtr *instruction, size_t index) {2402static 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}
29792984
2980static 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
2987static 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
2994static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) {2985static 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}
35243513
3525static 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
3539static 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
3548static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {3514static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
3549 assert(block_node->type == NodeTypeBlock);3515 assert(block_node->type == NodeTypeBlock);
35503516
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;
35543524
...@@ -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 }
35643534
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);
35703546
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 scope3558 // 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 expression3562 // 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 }
36313566
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
36373576
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 statement3578 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 void3583 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}
36513587
3652static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {3588static 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
45264462
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;
46954600
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
47804685
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 }
48064730
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}
48094733
4810static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {4734static 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;
48974821
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 }
49014825
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 }
49054834
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 node5013 // 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 }
50995028
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;
51035037
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}
51085040
5109static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) {5041static 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}
60175949
6018static 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
6034static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) {5950static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) {
6035 assert(node->type == NodeTypeCompTime);5951 assert(node->type == NodeTypeCompTime);
60365952
...@@ -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}
60405956
5957static 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
6041static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) {5982static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) {
6042 assert(node->type == NodeTypeBreak);5983 assert(node->type == NodeTypeBreak);
60435984
...@@ -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 loop5986 // * function definition scope or global scope => error, break outside loop
6046 // * defer expression scope => error, cannot break out of defer expression5987 // * defer expression scope => error, cannot break out of defer expression
6047 // * loop scope => OK5988 // * loop scope => OK
5989 // * (if it's a labeled break) labeled block => OK
60485990
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}
64536416
6454static 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
6518static void invalidate_exec(IrExecutable *exec) {6417static 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 }
65536452
6554 if (!ir_goto_pass2(irb)) {
6555 invalidate_exec(ir_executable);
6556 return false;
6557 }
6558
6559 return true;6453 return true;
6560}6454}
65616455
...@@ -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 }
74707364
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 anything7400 // 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)));
76187585
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
7664static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *type_entry) {7661static 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}
76717669
...@@ -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
82468243
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}
82588257
...@@ -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}
83728371
8372static 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
8373static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr,8429static 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 }
84498507
...@@ -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 }
89098977
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 anything9010 // 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
93379441
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
93989502
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}
1026710372
10373static 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
10268static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,10537static 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:
1044210711
10443static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,10712static 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
1070110970
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 }
1070710976
...@@ -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
1072510994
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);
1072910998
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;
1078511054
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);
1078811057
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
1083911108
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}
1218512454
12186static 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
12243static 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
12282static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,12455static 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);
1386814054
13869 ZigList<ErrorMsg *> errors = {0};14055 ZigList<ErrorMsg *> errors = {0};
1387014056
...@@ -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;
1573615922
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 }
1574015930
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 free16373 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}
887887
888static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instruction) {888static 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}
897901
898static 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
904static 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
911static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) {902static 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}
989980
981static 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
990999
991static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1000static 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}
634634
635/*
636GotoExpression = "goto" Symbol
637*/
638static 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/*
657CompTimeExpression(body) = "comptime" body636CompTimeExpression(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}
677656
678/*657/*
679PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl658PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol))
680KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"659KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
681*/660*/
682static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {661static 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;
746743
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;
752749
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 }
760764
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 }
769769
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;
793788
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;
803791
...@@ -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}
14841472
1485/*1473/*
1486BreakExpression : "break" option(Expression)1474BreakExpression = "break" option(":" Symbol) option(Expression)
1487*/1475*/
1488static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) {1476static 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);
14991494
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}
15351530
1536/*1531/*
1537VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression1532VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression
1538*/1533*/
1539static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory,1534static 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;
15441539
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
15771554
1578 AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_token);1555 AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_token);
15791556
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;
15831561
...@@ -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 }
16021580
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}
16141600
1601/*
1602GlobalVarDecl = option("export") VariableDeclaration ";"
1603*/
1604static 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/*
1624LocalVarDecl = option("comptime") VariableDeclaration
1625*/
1626static 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/*
1616BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression1646BoolOrExpression = 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}
16391669
1640/*1670/*
1641WhileExpression(body) = option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body))1671WhileExpression(body) = option(Symbol ":") option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body))
1642*/1672*/
1643static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1673static 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;
16461675
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;
16711719
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}
17271775
1728/*1776/*
1729ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body))1777ForExpression(body) = option(Symbol ":") option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body))
1730*/1778*/
1731static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1779static 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;
17341781
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 }
17571819
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;
17601825
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}
20842149
2085/*
2086Label: token(Symbol) token(Colon)
2087*/
2088static 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
2114static bool statement_terminates_without_semicolon(AstNode *node) {2150static 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}
21442179
2145/*2180/*
2146Block = "{" many(Statement) option(Expression) "}"2181Block = option(Symbol ":") "{" many(Statement) "}"
2147Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"2182Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ExportDecl
2148*/2183*/
2149static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) {2184static 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);
21512189
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;
21602215
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 }
21622220
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);
21732235
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 }
21872239
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);
21912241
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}
22062248
2207/*2249/*
2208FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("->" TypeExpr)2250FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("-&gt;" TypeExpr)
2209*/2251*/
2210static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {2252static 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;
22132255
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;
22412300
2242 Token *fn_name = &pc->tokens->at(*token_index);2301 Token *fn_name = &pc->tokens->at(*token_index);
22432302
...@@ -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}
22712338
2272/*2339/*
2273FnDef = option("inline" | "extern") FnProto Block2340FnDef = option("inline" | "export") FnProto Block
2274*/2341*/
2275static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {2342static 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 }
22912358
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 }
22992366
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;
23022369
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 }
23462413
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);
23502417
...@@ -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 }
24622526
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)
25532617
2554/*2618/*
2555TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl2619TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl
2556TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl)2620TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
2557*/2621*/
2558static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList<AstNode *> *top_level_decls) {2622static 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 }
26072668
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 // none2764 // 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);
104static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope);104static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope);
105static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope);105static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope);
106static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name);106static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name);
107static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope);
108107
109static TransScopeBlock *trans_scope_block_find(TransScope *scope);108static TransScopeBlock *trans_scope_block_find(TransScope *scope);
110static TransScopeSwitch *trans_scope_switch_find(TransScope *scope);
111109
112static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl);110static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl);
113static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl);111static 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}
175173
174static 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
181static 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
188static 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
176static AstNode *trans_create_node_float_lit(Context *c, double value) {196static 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}
259279
260static 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
266static 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
272static AstNode *trans_create_node_bool(Context *c, bool value) {280static 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
378386
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;
383390
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 case1157 // worst case
1151 // c: lhs = rhs1158 // 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: _tmp1162 // zig: break :x _tmp
1156 // zig: }1163 // zig: }
11571164
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;
11591168
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)));
11741183
1175 // _tmp1184 // 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));
11781187
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 >>= rhs1341 // 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: *_ref1345 // zig: break :x *_ref
1336 // zig: }1346 // zig: }
1337 // where u5 is the appropriate type1347 // where u5 is the appropriate type
13381348
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;
13401352
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);
13791391
1380 if (result_used == ResultUsedYes) {1392 if (result_used == ResultUsedYes) {
1381 // *_ref1393 // 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 }
13871399
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 += rhs1417 // 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: *_ref1421 // zig: break :x *_ref
1410 // zig: }1422 // zig: }
14111423
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;
14131427
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);
14381452
1439 // *_ref1453 // 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))));
14441458
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 case1750 // 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: _tmp1756 // 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;
17451761
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);
17691785
1770 // _tmp1786 // 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;
17731788
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 case1806 // worst case
1792 // c: ++expr1807 // 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: *_ref1811 // 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;
17991816
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);
18161833
1817 // *_ref1834 // 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;
18221838
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}
23762392
2377static 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
2438static 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
2481static 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
2516static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForStmt *stmt) {2393static 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) {
32463124
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}
38673746
3868static 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
3876static TransScopeBlock *trans_scope_block_find(TransScope *scope) {3747static 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}
38853756
3886static 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
3896static void render_aliases(Context *c) {3757static 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}
40053866
3867static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok_i);
3868static AstNode *parse_ctok_expr(Context *c, CTokenize *ctok, size_t *tok_i);
3869static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i);
3870
4006static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) {3871static 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}
40323897
4033static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {3898static 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 }
40823926
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 this3980 // not able to make sense of this
4094 return nullptr;3981 return nullptr;
4095 }3982 }
4096 zig_unreachable();3983 zig_unreachable();
4097}3984}
40983985
3986static 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
3990static 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
4017static 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}
4026static 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
4099static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) {4040static 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);
41014042
...@@ -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;
41104051
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
175175
176176
177LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,177LLVMValueRef 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 {
45bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,45bool 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);
4747
48enum ZigLLVM_FnInline {
49 ZigLLVM_FnInlineAuto,
50 ZigLLVM_FnInlineAlways,
51 ZigLLVM_FnInlineNever,
52};
48LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,53LLVMValueRef 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);
5055
51LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,56LLVMValueRef 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;
3const mem = @import("mem.zig");3const mem = @import("mem.zig");
4const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
55
6pub fn ArrayList(comptime T: type) -> type{6pub fn ArrayList(comptime T: type) -> type {
7 struct {7 return AlignedArrayList(T, @alignOf(T));
8}
9
10pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
11 return struct {
8 const Self = this;12 const Self = this;
913
10 /// Use toSlice instead of slicing this directly, because if you don't14 /// Use toSlice instead of slicing this directly, because if you don't
11 /// specify the end position of the slice, this will potentially give15 /// 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,
1620
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 }
2529
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 }
2933
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 }
3337
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 }
3741
38 /// ArrayList takes ownership of the passed in slice. The slice must have been42 /// 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 }
4852
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 }
6165
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 }
8791
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}
102112
103test "basic ArrayList test" {113test "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;
197197
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 }
4444
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 /// * ::replaceContentsBuffer30 /// * ::replaceContentsBuffer
31 /// * ::resize31 /// * ::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 }
3737
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 }
100100
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 }
104105
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 }
108110
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 }
118121
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 }
122125
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};
140148
141test "simple Buffer" {149test "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 }
222222
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 }
230230
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;
434434
435 const mode = if (release_safe and !release_fast) {435 const mode = if (release_safe and !release_fast)
436 builtin.Mode.ReleaseSafe436 builtin.Mode.ReleaseSafe
437 } else if (release_fast and !release_safe) {437 else if (release_fast and !release_safe)
438 builtin.Mode.ReleaseFast438 builtin.Mode.ReleaseFast
439 } else if (!release_fast and !release_safe) {439 else if (!release_fast and !release_safe)
440 builtin.Mode.Debug440 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.Debug444 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 }
507507
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 }
520520
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 {
590590
591 return error.UncleanExit;591 return error.UncleanExit;
592 },592 },
593 };593 }
594
595 }594 }
596595
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,
760817
...@@ -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 }
10191078
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_path1081 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 }
10271085
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 }
10361094
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_path1097 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 }
10441101
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 }
10711128
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 }
10761132
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);
10791139
...@@ -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 }
12241284
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 }
12341299
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 {
15441614
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 }
15601630
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,
18631933
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 }
18761946
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;
48pub extern "c" fn malloc(usize) -> ?&c_void;48pub extern "c" fn malloc(usize) -> ?&c_void;
49pub extern "c" fn realloc(&c_void, usize) -> ?&c_void;49pub extern "c" fn realloc(&c_void, usize) -> ?&c_void;
50pub extern "c" fn free(&c_void);50pub extern "c" fn free(&c_void);
51pub 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}
2222
23pub fn toSliceConst(str: &const u8) -> []const u8 {23pub 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}
3737
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 failure57 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";
96const DIM = "\x1b[2m";96const DIM = "\x1b[2m";
97const RESET = "\x1b[0m";97const RESET = "\x1b[0m";
9898
99pub var user_main_fn: ?fn() -> %void = null;
100
101error PathNotFound;99error PathNotFound;
102error InvalidDebugInfo;100error InvalidDebugInfo;
103101
...@@ -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);
131131
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 #313144 // 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}";
146146
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),
238239
...@@ -333,6 +334,15 @@ const Die = struct {...@@ -333,6 +334,15 @@ const Die = struct {
333 };334 };
334 }335 }
335336
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};
353363
...@@ -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) -> LineNumberProgram404 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 }
416426
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}
485492
486fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {493fn 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}
492499
493fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {500fn 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}
500504
501fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {505fn 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}
510510
511fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {511fn 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 },
557557
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}
570570
571fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {571fn 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;
844844
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 };
850848
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;
864862
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 + offset870 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 null879 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 null884 break :x null;
887 }885 }
888 };886 };
889887
...@@ -900,25 +898,51 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {...@@ -900,25 +898,51 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
900 }898 }
901}899}
902900
903fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> ?&const CompileUnit {901fn 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}
912936
913fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {937fn 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}
923947
924fn readULeb128(in_stream: &io.InStream) -> %u64 {948fn 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}
967991
968pub const global_allocator = &global_allocator_state;992pub const global_allocator = &global_fixed_allocator.allocator;
969var global_allocator_state = mem.Allocator {993var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);
970 .allocFn = globalAlloc,994var global_allocator_mem: [100 * 1024]u8 = undefined;
971 .reallocFn = globalRealloc,
972 .freeFn = globalFree,
973};
974995
975var some_mem: [100 * 1024]u8 = undefined;996/// Allocator that fails after N allocations, useful for making sure out of
976var some_mem_index: usize = 0;997/// memory conditions are handled correctly.
977998pub const FailingAllocator = struct {
978error 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 }
9791018
980fn 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}
9931029
994fn 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}
10031044
1004fn 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;
190190
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;
205205
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 }
220220
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;
245245
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;
248248
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);
251251
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 }
256256
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 }
264262
265 return null;263 return null;
266 }264 }
267265
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");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn swapIfLe(comptime T: type, x: T) -> T {4pub fn swapIfLe(comptime T: type, x: T) -> T {
5 swapIf(false, T, x)5 return swapIf(false, T, x);
6}6}
77
8pub fn swapIfBe(comptime T: type, x: T) -> T {8pub fn swapIfBe(comptime T: type, x: T) -> T {
9 swapIf(true, T, x)9 return swapIf(true, T, x);
10}10}
1111
12pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {12pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {
13 if (builtin.endian == endian) swap(T, x) else x13 return if (builtin.endian == endian) swap(T, x) else x;
14}14}
1515
16pub fn swap(comptime T: type, x: T) -> T {16pub 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};
440440
441fn slab(str: []const u8, exp: i32) -> Slab {441fn 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}
447447
448pub const enum3_data = []Slab {448pub 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.len257 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}
376379
377pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) -> %T {380pub 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};
415418
419error BufferTooSmall;
416fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) -> %void {420fn 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}
420425
421pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) -> []u8 {426pub 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}
426431
...@@ -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 }
506511
...@@ -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) -> type13 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 item54 unreachable; // no next item
55 }55 }
56 };56 };
5757
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 arithmetic64 // 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 }
6868
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 table136 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];
175175
...@@ -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 map213 unreachable; // put into a full map
214 }214 }
215215
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}
233233
234test "basicHashMapTest" {234test "basicHashMapTest" {
...@@ -251,9 +251,9 @@ test "basicHashMapTest" {...@@ -251,9 +251,9 @@ test "basicHashMapTest" {
251}251}
252252
253fn hash_i32(x: i32) -> u32 {253fn hash_i32(x: i32) -> u32 {
254 @bitCast(u32, x)254 return @bitCast(u32, x);
255}255}
256256
257fn eql_i32(a: i32, b: i32) -> bool {257fn eql_i32(a: i32, b: i32) -> bool {
258 a == b258 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;
1010
11error OutOfMemory;11error OutOfMemory;
1212
13pub var c_allocator = Allocator {13pub const c_allocator = &c_allocator_state;
14var c_allocator_state = Allocator {
14 .allocFn = cAlloc,15 .allocFn = cAlloc,
15 .reallocFn = cRealloc,16 .reallocFn = cRealloc,
16 .freeFn = cFree,17 .freeFn = cFree,
17};18};
1819
19fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {20fn 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.OutOfMemory24 error.OutOfMemory;
24 }
25}25}
2626
27fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {27fn 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}
3937
...@@ -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 }
108106
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 }
123121
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 @@
1pub const ArrayList = @import("array_list.zig").ArrayList;1pub const ArrayList = @import("array_list.zig").ArrayList;
2pub const AlignedArrayList = @import("array_list.zig").AlignedArrayList;
2pub const BufMap = @import("buf_map.zig").BufMap;3pub const BufMap = @import("buf_map.zig").BufMap;
3pub const BufSet = @import("buf_set.zig").BufSet;4pub const BufSet = @import("buf_set.zig").BufSet;
4pub const Buffer = @import("buffer.zig").Buffer;5pub const Buffer = @import("buffer.zig").Buffer;
6pub const BufferOutStream = @import("buffer.zig").BufferOutStream;
5pub const HashMap = @import("hash_map.zig").HashMap;7pub const HashMap = @import("hash_map.zig").HashMap;
6pub const LinkedList = @import("linked_list.zig").LinkedList;8pub const LinkedList = @import("linked_list.zig").LinkedList;
79
...@@ -26,12 +28,12 @@ pub const sort = @import("sort.zig");...@@ -26,12 +28,12 @@ pub const sort = @import("sort.zig");
2628
27test "std" {29test "std" {
28 // run tests from these30 // 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");
3537
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;
50error EndOfFile;50error EndOfFile;
5151
52pub fn getStdErr() -> %File {52pub 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_FILENO56 system.STDERR_FILENO
57 } else {57 else
58 unreachable58 unreachable;
59 };
60 return File.openHandle(handle);59 return File.openHandle(handle);
61}60}
6261
63pub fn getStdOut() -> %File {62pub 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_FILENO66 system.STDOUT_FILENO
68 } else {67 else
69 unreachable68 unreachable;
70 };
71 return File.openHandle(handle);69 return File.openHandle(handle);
72}70}
7371
74pub fn getStdIn() -> %File {72pub 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_FILENO76 system.STDIN_FILENO
79 } else {77 else
80 unreachable78 unreachable;
81 };
82 return File.openHandle(handle);79 return File.openHandle(handle);
83}80}
8481
...@@ -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 }
266263
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};
485490
486/// `path` may need to be copied in memory to add a null terminating byte. In this case491/// `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}
495500
501/// On success, caller owns returned buffer.
502pub 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
496pub const BufferedInStream = BufferedInStreamCustom(os.page_size);515pub const BufferedInStream = BufferedInStreamCustom(os.page_size);
497516
498pub fn BufferedInStreamCustom(comptime buffer_size: usize) -> type {517pub 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
643pub 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;
55
6/// Generic doubly linked list.6/// Generic doubly linked list.
7pub fn LinkedList(comptime T: type) -> type {7pub fn LinkedList(comptime T: type) -> type {
8 struct {8 return struct {
9 const Self = this;9 const Self = this;
1010
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,
1616
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 };
2525
...@@ -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 }
4141
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 }
171171
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}
196196
197test "basic linked list test" {197test "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;
77
8pub fn acos(x: var) -> @typeOf(x) {8pub 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}
1616
17fn r32(z: f32) -> f32 {17fn r32(z: f32) -> f32 {
...@@ -22,7 +22,7 @@ fn r32(z: f32) -> f32 {...@@ -22,7 +22,7 @@ fn r32(z: f32) -> f32 {
2222
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 / q25 return p / q;
26}26}
2727
28fn acos32(x: f32) -> f32 {28fn 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}
7474
75fn r64(z: f64) -> f64 {75fn r64(z: f64) -> f64 {
...@@ -86,7 +86,7 @@ fn r64(z: f64) -> f64 {...@@ -86,7 +86,7 @@ fn r64(z: f64) -> f64 {
8686
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 / q89 return p / q;
90}90}
9191
92fn acos64(x: f64) -> f64 {92fn 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}
143143
144test "math.acos" {144test "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;
99
10pub fn acosh(x: var) -> @typeOf(x) {10pub 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}
1818
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 {
2323
24 // |x| < 2, invalid if x < 1 or nan24 // |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| < 0x1p1228 // |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| >= 0x1p1232 // |x| >= 0x1p12
33 else {33 else {
34 math.ln(x) + 0.69314718055994530941723212145817656834 return math.ln(x) + 0.693147180559945309417232121458176568;
35 }35 }
36}36}
3737
...@@ -41,15 +41,15 @@ fn acosh64(x: f64) -> f64 {...@@ -41,15 +41,15 @@ fn acosh64(x: f64) -> f64 {
4141
42 // |x| < 2, invalid if x < 1 or nan42 // |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| < 0x1p2646 // |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 nan50 // |x| >= 0x1p26 or nan
51 else {51 else {
52 math.ln(x) + 0.69314718055994530941723212145817656852 return math.ln(x) + 0.693147180559945309417232121458176568;
53 }53 }
54}54}
5555
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;
88
9pub fn asin(x: var) -> @typeOf(x) {9pub 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}
1717
18fn r32(z: f32) -> f32 {18fn r32(z: f32) -> f32 {
...@@ -23,7 +23,7 @@ fn r32(z: f32) -> f32 {...@@ -23,7 +23,7 @@ fn r32(z: f32) -> f32 {
2323
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 / q26 return p / q;
27}27}
2828
29fn asin32(x: f32) -> f32 {29fn 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));
5959
60 if (hx >> 31 != 0) {60 if (hx >> 31 != 0) {
61 -fx61 return -fx;
62 } else {62 } else {
63 fx63 return fx;
64 }64 }
65}65}
6666
...@@ -78,7 +78,7 @@ fn r64(z: f64) -> f64 {...@@ -78,7 +78,7 @@ fn r64(z: f64) -> f64 {
7878
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 / q81 return p / q;
82}82}
8383
84fn asin64(x: f64) -> f64 {84fn asin64(x: f64) -> f64 {
...@@ -119,7 +119,7 @@ fn asin64(x: f64) -> f64 {...@@ -119,7 +119,7 @@ fn asin64(x: f64) -> f64 {
119119
120 // |x| > 0.975120 // |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 }
129129
130 if (hx >> 31 != 0) {130 if (hx >> 31 != 0) {
131 -fx131 return -fx;
132 } else {132 } else {
133 fx133 return fx;
134 }134 }
135}135}
136136
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;
99
10pub fn asinh(x: var) -> @typeOf(x) {10pub 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}
1818
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 }
4848
49 if (s != 0) -rx else rx49 return if (s != 0) -rx else rx;
50}50}
5151
52fn asinh64(x: f64) -> f64 {52fn 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 }
7979
80 if (s != 0) -rx else rx80 return if (s != 0) -rx else rx;
81}81}
8282
83test "math.asinh" {83test "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;
88
9pub fn atan(x: var) -> @typeOf(x) {9pub 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}
1717
18fn atan32(x_: f32) -> f32 {18fn 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]);
101101
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}
109109
...@@ -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]))));
200200
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}
208208
209test "math.atan" {209test "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}
213213
std/math/atan2.zig+10-10
...@@ -22,11 +22,11 @@ const math = @import("index.zig");...@@ -22,11 +22,11 @@ const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;22const assert = @import("../debug.zig").assert;
2323
24fn atan2(comptime T: type, x: T, y: T) -> T {24fn 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}
3131
32fn atan2_32(y: f32, x: f32) -> f32 {32fn 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 }
9898
99 // z = atan(|y / x|) with correct underflow99 // 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.0102 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 };
107107
...@@ -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 }
188188
189 // z = atan(|y / x|) with correct underflow189 // 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.0192 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 };
197197
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;
99
10pub fn atanh(x: var) -> @typeOf(x) {10pub 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}
1818
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 // underflow33 // 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.538 // |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 }
4545
46 if (s != 0) -y else y46 return if (s != 0) -y else y;
47}47}
4848
49fn atanh_64(x: f64) -> f64 {49fn 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 }
7474
75 if (s != 0) -y else y75 return if (s != 0) -y else y;
76}76}
7777
78test "math.atanh" {78test "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;
99
10pub fn cbrt(x: var) -> @typeOf(x) {10pub 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}
1818
19fn cbrt32(x: f32) -> f32 {19fn 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);
5555
56 f32(t)56 return f32(t);
57}57}
5858
59fn cbrt64(x: f64) -> f64 {59fn 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);
111111
112 t + t * q112 return t + t * q;
113}113}
114114
115test "math.cbrt" {115test "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;
1010
11pub fn ceil(x: var) -> @typeOf(x) {11pub 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}
1919
20fn ceil32(x: f32) -> f32 {20fn 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.048 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.075 return 1.0;
76 }76 }
77 } else if (y < 0) {77 } else if (y < 0) {
78 x + y + 178 return x + y + 1;
79 } else {79 } else {
80 x + y80 return x + y;
81 }81 }
82}82}
8383
std/math/copysign.zig+6-6
...@@ -2,11 +2,11 @@ const math = @import("index.zig");...@@ -2,11 +2,11 @@ const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;2const assert = @import("../debug.zig").assert;
33
4pub fn copysign(comptime T: type, x: T, y: T) -> T {4pub 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}
1111
12fn copysign32(x: f32, y: f32) -> f32 {12fn 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 {
1515
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}
2020
21fn copysign64(x: f64, y: f64) -> f64 {21fn 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 {
2424
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}
2929
30test "math.copysign" {30test "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;
99
10pub fn cos(x: var) -> @typeOf(x) {10pub 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}
1818
19// sin polynomial coefficients19// 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;
7575
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 };
8383
84 if (sign) {84 if (sign) {
85 -r85 return -r;
86 } else {86 } else {
87 r87 return r;
88 }88 }
89}89}
9090
...@@ -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;
126126
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 };
134134
135 if (sign) {135 if (sign) {
136 -r136 return -r;
137 } else {137 } else {
138 r138 return r;
139 }139 }
140}140}
141141
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;
1111
12pub fn cosh(x: var) -> @typeOf(x) {12pub 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}
2020
21// cosh(x) = (exp(x) + 1 / exp(x)) / 221// 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 }
4444
45 // |x| > log(FLT_MAX) or nan45 // |x| > log(FLT_MAX) or nan
46 expo2(ax)46 return expo2(ax);
47}47}
4848
49fn cosh64(x: f64) -> f64 {49fn cosh64(x: f64) -> f64 {
...@@ -76,7 +76,7 @@ fn cosh64(x: f64) -> f64 {...@@ -76,7 +76,7 @@ fn cosh64(x: f64) -> f64 {
76 }76 }
7777
78 // |x| > log(CBL_MAX) or nan78 // |x| > log(CBL_MAX) or nan
79 expo2(ax)79 return expo2(ax);
80}80}
8181
82test "math.cosh" {82test "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;
88
9pub fn exp(x: var) -> @typeOf(x) {9pub 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}
1717
18fn exp32(x_: f32) -> f32 {18fn 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);
8787
88 if (k == 0) {88 if (k == 0) {
89 y89 return y;
90 } else {90 } else {
91 math.scalbn(y, k)91 return math.scalbn(y, k);
92 }92 }
93}93}
9494
...@@ -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);
173173
174 if (k == 0) {174 if (k == 0) {
175 y175 return y;
176 } else {176 } else {
177 math.scalbn(y, k)177 return math.scalbn(y, k);
178 }178 }
179}179}
180180
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;
88
9pub fn exp2(x: var) -> @typeOf(x) {9pub 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}
1717
18const exp2ft = []const f64 {18const 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}
9393
94const exp2dt = []f64 {94const 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))));
416416
417 math.scalbn(r, ik)417 return math.scalbn(r, ik);
418}418}
419419
420test "math.exp2" {420test "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;
99
10pub fn expm1(x: var) -> @typeOf(x) {10pub 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}
1818
19fn expm1_32(x_: f32) -> f32 {19fn 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");
22
3pub fn expo2(x: var) -> @typeOf(x) {3pub 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}
1111
12fn expo2f(x: f32) -> f32 {12fn expo2f(x: f32) -> f32 {
...@@ -15,7 +15,7 @@ fn expo2f(x: f32) -> f32 {...@@ -15,7 +15,7 @@ fn expo2f(x: f32) -> f32 {
1515
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 * scale18 return math.exp(x - kln2) * scale * scale;
19}19}
2020
21fn expo2d(x: f64) -> f64 {21fn expo2d(x: f64) -> f64 {
...@@ -24,5 +24,5 @@ fn expo2d(x: f64) -> f64 {...@@ -24,5 +24,5 @@ fn expo2d(x: f64) -> f64 {
2424
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 * scale27 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;
88
9pub fn fabs(x: var) -> @typeOf(x) {9pub 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}
1717
18fn fabs32(x: f32) -> f32 {18fn 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}
2323
24fn fabs64(x: f64) -> f64 {24fn 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}
2929
30test "math.fabs" {30test "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");
1010
11pub fn floor(x: var) -> @typeOf(x) {11pub 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}
1919
20fn floor32(x: f32) -> f32 {20fn 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 return47 return 0.0;
48 } else {48 } else {
49 -1.049 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.076 return 0.0;
77 }77 }
78 } else if (y > 0) {78 } else if (y > 0) {
79 x + y - 179 return x + y - 1;
80 } else {80 } else {
81 x + y81 return x + y;
82 }82 }
83}83}
8484
std/math/fma.zig+12-12
...@@ -2,11 +2,11 @@ const math = @import("index.zig");...@@ -2,11 +2,11 @@ const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;2const assert = @import("../debug.zig").assert;
33
4pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {4pub 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}
1111
12fn fma32(x: f32, y: f32, z: f32) -> f32 {12fn 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;
1717
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-rounding21 // TODO: Handle inexact case with double-rounding
22 f32(xy_z)22 return f32(xy_z);
23 }23 }
24}24}
2525
...@@ -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 {
6464
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}
7272
...@@ -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 ret80 return ret;
81}81}
8282
83fn dd_mul(a: f64, b: f64) -> dd {83fn 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 {
9999
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 ret102 return ret;
103}103}
104104
105fn add_adjusted(a: f64, b: f64) -> f64 {105fn 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.hi116 return sum.hi;
117}117}
118118
119fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 {119fn 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}
132132
133test "math.fma" {133test "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");
8const assert = @import("../debug.zig").assert;8const assert = @import("../debug.zig").assert;
99
10fn frexp_result(comptime T: type) -> type {10fn 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}
16pub const frexp32_result = frexp_result(f32);16pub const frexp32_result = frexp_result(f32);
17pub const frexp64_result = frexp_result(f64);17pub const frexp64_result = frexp_result(f64);
1818
19pub fn frexp(x: var) -> frexp_result(@typeOf(x)) {19pub 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}
2727
28fn frexp32(x: f32) -> frexp32_result {28fn 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 result62 return result;
63}63}
6464
65fn frexp64(x: f64) -> frexp64_result {65fn 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 result99 return result;
100}100}
101101
102test "math.frexp" {102test "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");
9const assert = @import("../debug.zig").assert;9const assert = @import("../debug.zig").assert;
1010
11pub fn hypot(comptime T: type, x: T, y: T) -> T {11pub 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}
1818
19fn hypot32(x: f32, y: f32) -> f32 {19fn 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 }
5050
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}
5353
54fn sq(hi: &f64, lo: &f64, x: f64) {54fn 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);
111111
112 z * math.sqrt(ly + lx + hy + hx)112 return z * math.sqrt(ly + lx + hy + hx);
113}113}
114114
115test "math.hypot" {115test "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;
99
10pub fn ilogb(x: var) -> i32 {10pub 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}
1818
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 }
5555
56 e - 0x7F56 return e - 0x7F;
57}57}
5858
59fn ilogb64(x: f64) -> i32 {59fn 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 }
9090
91 e - 0x3FF91 return e - 0x3FF;
92}92}
9393
94test "math.ilogb" {94test "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;
3636
37pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) -> bool {37pub 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) < epsilon39 return fabs(x - y) < epsilon;
40}40}
4141
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}
175175
176176
177pub const Cmp = enum {
178 Less,
179 Equal,
180 Greater,
181};
182
183pub fn min(x: var, y: var) -> @typeOf(x + y) {177pub fn min(x: var, y: var) -> @typeOf(x + y) {
184 if (x < y) x else y178 return if (x < y) x else y;
185}179}
186180
187test "math.min" {181test "math.min" {
...@@ -189,7 +183,7 @@ test "math.min" {...@@ -189,7 +183,7 @@ test "math.min" {
189}183}
190184
191pub fn max(x: var, y: var) -> @typeOf(x + y) {185pub fn max(x: var, y: var) -> @typeOf(x + y) {
192 if (x > y) x else y186 return if (x > y) x else y;
193}187}
194188
195test "math.max" {189test "math.max" {
...@@ -199,19 +193,19 @@ test "math.max" {...@@ -199,19 +193,19 @@ test "math.max" {
199error Overflow;193error Overflow;
200pub fn mul(comptime T: type, a: T, b: T) -> %T {194pub 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 answer196 return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
203}197}
204198
205error Overflow;199error Overflow;
206pub fn add(comptime T: type, a: T, b: T) -> %T {200pub 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 answer202 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
209}203}
210204
211error Overflow;205error Overflow;
212pub fn sub(comptime T: type, a: T, b: T) -> %T {206pub 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 answer208 return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
215}209}
216210
217pub fn negate(x: var) -> %@typeOf(x) {211pub 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) {
221error Overflow;215error Overflow;
222pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) -> %T {216pub 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 answer218 return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
225}219}
226220
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}
274268
275pub fn Log2Int(comptime T: type) -> type {269pub fn Log2Int(comptime T: type) -> type {
276 @IntType(false, log2(T.bit_count))270 return @IntType(false, log2(T.bit_count));
277}271}
278272
279test "math overflow functions" {273test "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
520pub 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
531test "math.floorPowerOfTwo" {
532 testFloorPowerOfTwo();
533 comptime testFloorPowerOfTwo();
534}
535
536fn 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");
2const assert = @import("../debug.zig").assert;2const assert = @import("../debug.zig").assert;
33
4pub fn inf(comptime T: type) -> T {4pub 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 < 0x7F8000009 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 == 0x7F8000009 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) == 0x7F80000025 return @bitCast(u32, x) == 0x7F800000;
26 },26 },
27 f64 => {27 f64 => {
28 @bitCast(u64, x) == 0x7FF << 5228 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) == 0xFF80000040 return @bitCast(u32, x) == 0xFF800000;
41 },41 },
42 f64 => {42 f64 => {
43 @bitCast(u64, x) == 0xFFF << 5243 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 > 0x7F8000009 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 bit21// 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.
23pub fn isSignalNan(x: var) -> bool {23pub fn isSignalNan(x: var) -> bool {
24 isNan(x)24 return isNan(x);
25}25}
2626
27test "math.isNan" {27test "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 >= 0x010000009 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);
8686
87 s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi87 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
88}88}
8989
90pub fn ln_64(x_: f64) -> f64 {90pub 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 x116 // 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);
144144
145 s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi145 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
146}146}
147147
148test "math.ln" {148test "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 },
3434
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);
9292
93 dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi93 return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi;
94}94}
9595
96pub fn log10_64(x_: f64) -> f64 {96pub 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 x124 // 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;
169169
170 val_lo + val_hi170 return val_lo + val_hi;
171}171}
172172
173test "math.log10" {173test "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;
1111
12pub fn log1p(x: var) -> @typeOf(x) {12pub 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}
2020
21fn log1p_32(x: f32) -> f32 {21fn 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);
9393
94 s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi94 return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
95}95}
9696
97fn log1p_64(x: f64) -> f64 {97fn 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);
174174
175 s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi175 return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
176}176}
177177
178test "math.log1p" {178test "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}
9999
100pub fn log2_64(x_: f64) -> f64 {100pub 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;
167167
168 val_lo + val_hi168 return val_lo + val_hi;
169}169}
170170
171test "math.log2" {171test "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");
7const assert = @import("../debug.zig").assert;7const assert = @import("../debug.zig").assert;
88
9fn modf_result(comptime T: type) -> type {9fn 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}
15pub const modf32_result = modf_result(f32);15pub const modf32_result = modf_result(f32);
16pub const modf64_result = modf_result(f64);16pub const modf64_result = modf_result(f64);
1717
18pub fn modf(x: var) -> modf_result(@typeOf(x)) {18pub 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}
2626
27fn modf32(x: f32) -> modf32_result {27fn 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 result69 return result;
70}70}
7171
72fn modf64(x: f64) -> modf64_result {72fn 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 result113 return result;
114}114}
115115
116test "math.modf" {116test "math.modf" {
std/math/nan.zig+4-4
...@@ -1,19 +1,19 @@...@@ -1,19 +1,19 @@
1const math = @import("index.zig");1const math = @import("index.zig");
22
3pub fn nan(comptime T: type) -> T {3pub 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}
1010
11// Note: A signalling nan is identical to a standard right now by may have a different bit11// 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.
13pub fn snan(comptime T: type) -> T {13pub 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 }
168168
169 math.scalbn(a1, ae)169 return math.scalbn(a1, ae);
170}170}
171171
172fn isOddInteger(x: f64) -> bool {172fn 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 == 1174 return r.fpart == 0.0 and i64(r.ipart) & 1 == 1;
175}175}
176176
177test "math.pow" {177test "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");
1010
11pub fn round(x: var) -> @typeOf(x) {11pub 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}
1919
20fn round32(x_: f32) -> f32 {20fn round32(x_: f32) -> f32 {
...@@ -48,9 +48,9 @@ fn round32(x_: f32) -> f32 {...@@ -48,9 +48,9 @@ fn round32(x_: f32) -> f32 {
48 }48 }
4949
50 if (u >> 31 != 0) {50 if (u >> 31 != 0) {
51 -y51 return -y;
52 } else {52 } else {
53 y53 return y;
54 }54 }
55}55}
5656
...@@ -85,9 +85,9 @@ fn round64(x_: f64) -> f64 {...@@ -85,9 +85,9 @@ fn round64(x_: f64) -> f64 {
85 }85 }
8686
87 if (u >> 63 != 0) {87 if (u >> 63 != 0) {
88 -y88 return -y;
89 } else {89 } else {
90 y90 return y;
91 }91 }
92}92}
9393
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;
33
4pub fn scalbn(x: var, n: i32) -> @typeOf(x) {4pub 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}
1212
13fn scalbn32(x: f32, n_: i32) -> f32 {13fn 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 }
3838
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}
4242
43fn scalbn64(x: f64, n_: i32) -> f64 {43fn 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 }
6868
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}
7272
73test "math.scalbn" {73test "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;
33
4pub fn signbit(x: var) -> bool {4pub 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}
1212
13fn signbit32(x: f32) -> bool {13fn signbit32(x: f32) -> bool {
14 const bits = @bitCast(u32, x);14 const bits = @bitCast(u32, x);
15 bits >> 31 != 015 return bits >> 31 != 0;
16}16}
1717
18fn signbit64(x: f64) -> bool {18fn signbit64(x: f64) -> bool {
19 const bits = @bitCast(u64, x);19 const bits = @bitCast(u64, x);
20 bits >> 63 != 020 return bits >> 63 != 0;
21}21}
2222
23test "math.signbit" {23test "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;
1010
11pub fn sin(x: var) -> @typeOf(x) {11pub 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}
1919
20// sin polynomial coefficients20// 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;
7777
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 };
8585
86 if (sign) {86 if (sign) {
87 -r87 return -r;
88 } else {88 } else {
89 r89 return r;
90 }90 }
91}91}
9292
...@@ -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;
129129
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 };
137137
138 if (sign) {138 if (sign) {
139 -r139 return -r;
140 } else {140 } else {
141 r141 return r;
142 }142 }
143}143}
144144
145test "math.sin" {145test "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}
150150
151test "math.sin32" {151test "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;
1111
12pub fn sinh(x: var) -> @typeOf(x) {12pub 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}
2020
21// sinh(x) = (exp(x) - 1 / exp(x)) / 221// 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 }
5050
51 // |x| > log(FLT_MAX) or nan51 // |x| > log(FLT_MAX) or nan
52 2 * h * expo2(ax)52 return 2 * h * expo2(ax);
53}53}
5454
55fn sinh64(x: f64) -> f64 {55fn sinh64(x: f64) -> f64 {
...@@ -83,7 +83,7 @@ fn sinh64(x: f64) -> f64 {...@@ -83,7 +83,7 @@ fn sinh64(x: f64) -> f64 {
83 }83 }
8484
85 // |x| > log(DBL_MAX) or nan85 // |x| > log(DBL_MAX) or nan
86 2 * h * expo2(ax)86 return 2 * h * expo2(ax);
87}87}
8888
89test "math.sinh" {89test "math.sinh" {
std/math/sqrt.zig+62-8
...@@ -7,12 +7,34 @@...@@ -7,12 +7,34 @@
77
8const math = @import("index.zig");8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;9const assert = @import("../debug.zig").assert;
10const builtin = @import("builtin");
11const TypeId = builtin.TypeId;
1012
11pub fn sqrt(x: var) -> @typeOf(x) {13pub 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 // subnormal64 // 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 <<= 167 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 {
90112
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}
95117
96// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound118// 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 // subnormal153 // 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 <<= 1156 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);
224246
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}
228250
229test "math.sqrt" {251test "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
300fn 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
323test "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;
1010
11pub fn tan(x: var) -> @typeOf(x) {11pub 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}
1919
20const Tp0 = -1.30936939181383777646E4;20const 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;
6464
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 z69 break :r z;
70 }70 }
71 };71 };
7272
...@@ -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 }
7979
80 r80 return r;
81}81}
8282
83fn tan64(x_: f64) -> f64 {83fn 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;
113113
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 z118 break :r z;
119 }119 }
120 };120 };
121121
...@@ -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 }
128128
129 r129 return r;
130}130}
131131
132test "math.tan" {132test "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;
1111
12pub fn tanh(x: var) -> @typeOf(x) {12pub 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}
2020
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 }
6060
61 if (u >> 31 != 0) {61 if (u >> 31 != 0) {
62 -t62 return -t;
63 } else {63 } else {
64 t64 return t;
65 }65 }
66}66}
6767
...@@ -104,9 +104,9 @@ fn tanh64(x: f64) -> f64 {...@@ -104,9 +104,9 @@ fn tanh64(x: f64) -> f64 {
104 }104 }
105105
106 if (u >> 63 != 0) {106 if (u >> 63 != 0) {
107 -t107 return -t;
108 } else {108 } else {
109 t109 return t;
110 }110 }
111}111}
112112
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;
99
10pub fn trunc(x: var) -> @typeOf(x) {10pub 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}
1818
19fn trunc32(x: f32) -> f32 {19fn trunc32(x: f32) -> f32 {
...@@ -30,10 +30,10 @@ fn trunc32(x: f32) -> f32 {...@@ -30,10 +30,10 @@ fn trunc32(x: f32) -> f32 {
3030
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 x33 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}
3939
...@@ -51,10 +51,10 @@ fn trunc64(x: f64) -> f64 {...@@ -51,10 +51,10 @@ fn trunc64(x: f64) -> f64 {
5151
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 x54 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}
6060
std/mem.zig+149-36
...@@ -3,26 +3,31 @@ const assert = debug.assert;...@@ -3,26 +3,31 @@ const assert = debug.assert;
3const math = @import("math/index.zig");3const math = @import("math/index.zig");
4const builtin = @import("builtin");4const builtin = @import("builtin");
55
6pub const Cmp = math.Cmp;6error OutOfMemory;
77
8pub const Allocator = struct {8pub const Allocator = struct {
9 /// Allocate byte_count bytes and return them in a slice, with the9 /// 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,
1213
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.ptr15 /// * `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 must18 /// 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,
1924
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),
2227
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 }
2732
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 }
3136
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 }
3752
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 }
4263
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 }
5073
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 {
5988
60 assert(n <= old_mem.len);89 assert(n <= old_mem.len);
6190
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 because91 // 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;
6894
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 }
7298
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};
81107
108pub 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
82153
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}
97168
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.170pub fn lessThan(comptime T: type, lhs: []const T, rhs: []const T) -> bool {
100pub 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 }
107177
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
181test "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}
110188
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.
278pub fn split(buffer: []const u8, split_bytes: []const u8) -> SplitIterator {356pub 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}
285363
286test "mem.split" {364test "mem.split" {
...@@ -433,9 +511,8 @@ fn testWriteIntImpl() {...@@ -433,9 +511,8 @@ fn testWriteIntImpl() {
433511
434pub fn min(comptime T: type, slice: []const T) -> T {512pub 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" {
446523
447pub fn max(comptime T: type, slice: []const T) -> T {524pub 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 {
456test "mem.max" {532test "mem.max" {
457 assert(max(u8, "abcdefg") == 'g');533 assert(max(u8, "abcdefg") == 'g');
458}534}
535
536pub 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
543pub 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
551test "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
560pub 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
566test "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 // TODO75 unreachable; // TODO
76 }76 }
7777
78 // TODO78 // 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 //};
8686
87 unreachable // TODO87 unreachable; // TODO
88}88}
8989
90pub fn connectAddr(addr: &Address, port: u16) -> %Connection {90pub 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);
9898
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 unreachable115 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 {
165fn hexDigit(c: u8) -> u8 {165fn hexDigit(c: u8) -> u8 {
166 // TODO use switch with range166 // 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' + 10170 return c - 'A' + 10;
171 } else if ('a' <= c and c <= 'z') {171 } else if ('a' <= c and c <= 'z') {
172 c - 'a' + 10172 return c - 'a' + 10;
173 } else {173 } else {
174 @maxValue(u8)174 return @maxValue(u8);
175 }175 }
176}176}
177177
std/os/child_process.zig+82-40
...@@ -5,7 +5,6 @@ const os = std.os;...@@ -5,7 +5,6 @@ const os = std.os;
5const posix = os.posix;5const posix = os.posix;
6const windows = os.windows;6const windows = os.windows;
7const mem = std.mem;7const mem = std.mem;
8const Allocator = mem.Allocator;
9const debug = std.debug;8const debug = std.debug;
10const assert = debug.assert;9const assert = debug.assert;
11const BufMap = std.BufMap;10const BufMap = std.BufMap;
...@@ -74,7 +73,7 @@ pub const ChildProcess = struct {...@@ -74,7 +73,7 @@ pub const ChildProcess = struct {
7473
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);
8079
...@@ -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 }
121120
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 }
182181
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);
212251
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 });
221260
...@@ -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 }
265304
266 // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after305 // 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 child306 // 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 }
281320
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 }
293332
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); };
306345
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 undefined350 undefined
312 };351 ;
313 defer { if (any_ignore) os.close(dev_null_fd); };352 defer { if (any_ignore) os.close(dev_null_fd); }
314353
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_map358 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_owned362 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(); }
326365
...@@ -411,13 +450,13 @@ pub const ChildProcess = struct {...@@ -411,13 +450,13 @@ pub const ChildProcess = struct {
411 self.stdout_behavior == StdIo.Ignore or450 self.stdout_behavior == StdIo.Ignore or
412 self.stderr_behavior == StdIo.Ignore);451 self.stderr_behavior == StdIo.Ignore);
413452
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 undefined457 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;
505544
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 null548 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;
513552
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 null556 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;
521560
522 // the cwd set in ChildProcess is in effect when choosing the executable path561 // the cwd set in ChildProcess is in effect when choosing the executable path
523 // to match posix semantics562 // 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);
532573
...@@ -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};
593635
594fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8,636fn 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: ?
611653
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].
614fn windowsCreateCommandLine(allocator: &Allocator, argv: []const []const u8) -> %[]u8 {656fn 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();
617659
...@@ -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}
762804
763const sigchld_set = {805const 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_set808 break :x signal_set;
767};809};
768810
769fn block_SIGCHLD() {811fn 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
97pub const SIGUSR1 = 30; /// user defined signal 197pub const SIGUSR1 = 30; /// user defined signal 1
98pub const SIGUSR2 = 31; /// user defined signal 298pub const SIGUSR2 = 31; /// user defined signal 2
9999
100fn wstatus(x: i32) -> i32 { x & 0o177 }100fn wstatus(x: i32) -> i32 { return x & 0o177; }
101const wstopped = 0o177;101const wstopped = 0o177;
102pub fn WEXITSTATUS(x: i32) -> i32 { x >> 8 }102pub fn WEXITSTATUS(x: i32) -> i32 { return x >> 8; }
103pub fn WTERMSIG(x: i32) -> i32 { wstatus(x) }103pub fn WTERMSIG(x: i32) -> i32 { return wstatus(x); }
104pub fn WSTOPSIG(x: i32) -> i32 { x >> 8 }104pub fn WSTOPSIG(x: i32) -> i32 { return x >> 8; }
105pub fn WIFEXITED(x: i32) -> bool { wstatus(x) == 0 }105pub fn WIFEXITED(x: i32) -> bool { return wstatus(x) == 0; }
106pub fn WIFSTOPPED(x: i32) -> bool { wstatus(x) == wstopped and WSTOPSIG(x) != 0x13 }106pub fn WIFSTOPPED(x: i32) -> bool { return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; }
107pub fn WIFSIGNALED(x: i32) -> bool { wstatus(x) != wstopped and wstatus(x) != 0 }107pub fn WIFSIGNALED(x: i32) -> bool { return wstatus(x) != wstopped and wstatus(x) != 0; }
108108
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.
110pub fn getErrno(r: usize) -> usize {110pub 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 0112 return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
113}113}
114114
115pub fn close(fd: i32) -> usize {115pub fn close(fd: i32) -> usize {
116 errnoWrap(c.close(fd))116 return errnoWrap(c.close(fd));
117}117}
118118
119pub fn abort() -> noreturn {119pub fn abort() -> noreturn {
120 c.abort()120 c.abort();
121}121}
122122
123pub fn exit(code: i32) -> noreturn {123pub fn exit(code: i32) -> noreturn {
124 c.exit(code)124 c.exit(code);
125}125}
126126
127pub fn isatty(fd: i32) -> bool {127pub fn isatty(fd: i32) -> bool {
128 c.isatty(fd) != 0128 return c.isatty(fd) != 0;
129}129}
130130
131pub fn fstat(fd: i32, buf: &c.Stat) -> usize {131pub 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}
134134
135pub fn lseek(fd: i32, offset: isize, whence: c_int) -> usize {135pub 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}
138138
139pub fn open(path: &const u8, flags: u32, mode: usize) -> usize {139pub 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}
142142
143pub fn raise(sig: i32) -> usize {143pub fn raise(sig: i32) -> usize {
144 errnoWrap(c.raise(sig))144 return errnoWrap(c.raise(sig));
145}145}
146146
147pub fn read(fd: i32, buf: &u8, nbyte: usize) -> usize {147pub 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}
150150
151pub fn stat(noalias path: &const u8, noalias buf: &stat) -> usize {151pub 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}
154154
155pub fn write(fd: i32, buf: &const u8, nbyte: usize) -> usize {155pub 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}
158158
159pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32,159pub 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}
167167
168pub fn munmap(address: &u8, length: usize) -> usize {168pub 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}
171171
172pub fn unlink(path: &const u8) -> usize {172pub fn unlink(path: &const u8) -> usize {
173 errnoWrap(c.unlink(path))173 return errnoWrap(c.unlink(path));
174}174}
175175
176pub fn getcwd(buf: &u8, size: usize) -> usize {176pub fn getcwd(buf: &u8, size: usize) -> usize {
177 if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0177 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0;
178}178}
179179
180pub fn waitpid(pid: i32, status: &i32, options: u32) -> usize {180pub 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}
184184
185pub fn fork() -> usize {185pub fn fork() -> usize {
186 errnoWrap(c.fork())186 return errnoWrap(c.fork());
187}187}
188188
189pub fn pipe(fds: &[2]i32) -> usize {189pub 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}
193193
194pub fn mkdir(path: &const u8, mode: u32) -> usize {194pub fn mkdir(path: &const u8, mode: u32) -> usize {
195 errnoWrap(c.mkdir(path, mode))195 return errnoWrap(c.mkdir(path, mode));
196}196}
197197
198pub fn symlink(existing: &const u8, new: &const u8) -> usize {198pub fn symlink(existing: &const u8, new: &const u8) -> usize {
199 errnoWrap(c.symlink(existing, new))199 return errnoWrap(c.symlink(existing, new));
200}200}
201201
202pub fn rename(old: &const u8, new: &const u8) -> usize {202pub fn rename(old: &const u8, new: &const u8) -> usize {
203 errnoWrap(c.rename(old, new))203 return errnoWrap(c.rename(old, new));
204}204}
205205
206pub fn chdir(path: &const u8) -> usize {206pub fn chdir(path: &const u8) -> usize {
207 errnoWrap(c.chdir(path))207 return errnoWrap(c.chdir(path));
208}208}
209209
210pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8)210pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8)
211 -> usize211 -> usize
212{212{
213 errnoWrap(c.execve(path, argv, envp))213 return errnoWrap(c.execve(path, argv, envp));
214}214}
215215
216pub fn dup2(old: i32, new: i32) -> usize {216pub fn dup2(old: i32, new: i32) -> usize {
217 errnoWrap(c.dup2(old, new))217 return errnoWrap(c.dup2(old, new));
218}218}
219219
220pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {220pub 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}
223223
224pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize {224pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize {
225 errnoWrap(c.nanosleep(req, rem))225 return errnoWrap(c.nanosleep(req, rem));
226}226}
227227
228pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) -> usize {228pub 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 0229 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0;
230}230}
231231
232pub fn setreuid(ruid: u32, euid: u32) -> usize {232pub fn setreuid(ruid: u32, euid: u32) -> usize {
233 errnoWrap(c.setreuid(ruid, euid))233 return errnoWrap(c.setreuid(ruid, euid));
234}234}
235235
236pub fn setregid(rgid: u32, egid: u32) -> usize {236pub fn setregid(rgid: u32, egid: u32) -> usize {
237 errnoWrap(c.setregid(rgid, egid))237 return errnoWrap(c.setregid(rgid, egid));
238}238}
239239
240pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {240pub 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}
243243
244pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {244pub 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 make285/// that the kernel represents it to libc. Errno was a mistake, let's make
286/// it go away forever.286/// it go away forever.
287fn errnoWrap(value: isize) -> usize {287fn 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 default157 // 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 };
164163
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}
686685
...@@ -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 implementation902// TODO non-recursive implementation
904pub fn deleteTree(allocator: &Allocator, full_path: []const u8) -> %void {903pub fn deleteTree(allocator: &Allocator, full_path: []const u8) -> %void {
905start_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();
924923
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();
927926
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);
934933
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}
940940
941pub const Dir = struct {941pub 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 invalid988 /// 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 }
996996
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;
10201020
1021 const name = cstr.toSlice(&linux_entry.d_name);1021 const name = cstr.toSlice(&linux_entry.d_name);
10221022
1023 // skip . and .. entries1023 // 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 }
10271027
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};
10451046
...@@ -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}
14241425
1426/// Caller must call freeArgs on result.
1427pub 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
1464pub 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
1425test "windows arg parsing" {1474test "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}
14961545
1546/// Get the directory path that contains the current executable.
1547/// Caller owns returned memory.
1548pub 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
1497pub fn isTty(handle: FileHandle) -> bool {1579pub 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;
367pub const TFD_TIMER_ABSTIME = 1;367pub const TFD_TIMER_ABSTIME = 1;
368pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);368pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
369369
370fn unsigned(s: i32) -> u32 { @bitCast(u32, s) }370fn unsigned(s: i32) -> u32 { return @bitCast(u32, s); }
371fn signed(s: u32) -> i32 { @bitCast(i32, s) }371fn signed(s: u32) -> i32 { return @bitCast(i32, s); }
372pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) }372pub fn WEXITSTATUS(s: i32) -> i32 { return signed((unsigned(s) & 0xff00) >> 8); }
373pub fn WTERMSIG(s: i32) -> i32 { signed(unsigned(s) & 0x7f) }373pub fn WTERMSIG(s: i32) -> i32 { return signed(unsigned(s) & 0x7f); }
374pub fn WSTOPSIG(s: i32) -> i32 { WEXITSTATUS(s) }374pub fn WSTOPSIG(s: i32) -> i32 { return WEXITSTATUS(s); }
375pub fn WIFEXITED(s: i32) -> bool { WTERMSIG(s) == 0 }375pub fn WIFEXITED(s: i32) -> bool { return WTERMSIG(s) == 0; }
376pub fn WIFSTOPPED(s: i32) -> bool { (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00 }376pub fn WIFSTOPPED(s: i32) -> bool { return (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00; }
377pub fn WIFSIGNALED(s: i32) -> bool { (unsigned(s)&0xffff)-%1 < 0xff }377pub fn WIFSIGNALED(s: i32) -> bool { return (unsigned(s)&0xffff)-%1 < 0xff; }
378378
379379
380pub const winsize = extern struct {380pub 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.
388pub fn getErrno(r: usize) -> usize {388pub 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 0390 return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
391}391}
392392
393pub fn dup2(old: i32, new: i32) -> usize {393pub 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}
396396
397pub fn chdir(path: &const u8) -> usize {397pub 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}
400400
401pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {401pub 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}
404404
405pub fn fork() -> usize {405pub fn fork() -> usize {
406 arch.syscall0(arch.SYS_fork)406 return arch.syscall0(arch.SYS_fork);
407}407}
408408
409pub fn getcwd(buf: &u8, size: usize) -> usize {409pub 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}
412412
413pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize {413pub 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}
416416
417pub fn isatty(fd: i32) -> bool {417pub 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}
421421
422pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {422pub 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}
425425
426pub fn mkdir(path: &const u8, mode: u32) -> usize {426pub 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}
429429
430pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize)430pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize)
431 -> usize431 -> 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}
436436
437pub fn munmap(address: &u8, length: usize) -> usize {437pub 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}
440440
441pub fn read(fd: i32, buf: &u8, count: usize) -> usize {441pub 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}
444444
445pub fn rmdir(path: &const u8) -> usize {445pub 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}
448448
449pub fn symlink(existing: &const u8, new: &const u8) -> usize {449pub 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}
452452
453pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {453pub 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}
456456
457pub fn pipe(fd: &[2]i32) -> usize {457pub fn pipe(fd: &[2]i32) -> usize {
458 pipe2(fd, 0)458 return pipe2(fd, 0);
459}459}
460460
461pub fn pipe2(fd: &[2]i32, flags: usize) -> usize {461pub 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}
464464
465pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {465pub 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}
468468
469pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize {469pub 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}
472472
473pub fn rename(old: &const u8, new: &const u8) -> usize {473pub 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}
476476
477pub fn open(path: &const u8, flags: u32, perm: usize) -> usize {477pub 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}
480480
481pub fn create(path: &const u8, perm: usize) -> usize {481pub 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}
484484
485pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize {485pub 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}
488488
489pub fn close(fd: i32) -> usize {489pub fn close(fd: i32) -> usize {
490 arch.syscall1(arch.SYS_close, usize(fd))490 return arch.syscall1(arch.SYS_close, usize(fd));
491}491}
492492
493pub fn lseek(fd: i32, offset: isize, ref_pos: usize) -> usize {493pub 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}
496496
497pub fn exit(status: i32) -> noreturn {497pub 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 unreachable499 unreachable;
500}500}
501501
502pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize {502pub 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}
505505
506pub fn kill(pid: i32, sig: i32) -> usize {506pub 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}
509509
510pub fn unlink(path: &const u8) -> usize {510pub 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}
513513
514pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize {514pub 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}
517517
518pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize {518pub 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}
521521
522pub fn setuid(uid: u32) -> usize {522pub fn setuid(uid: u32) -> usize {
523 arch.syscall1(arch.SYS_setuid, uid)523 return arch.syscall1(arch.SYS_setuid, uid);
524}524}
525525
526pub fn setgid(gid: u32) -> usize {526pub fn setgid(gid: u32) -> usize {
527 arch.syscall1(arch.SYS_setgid, gid)527 return arch.syscall1(arch.SYS_setgid, gid);
528}528}
529529
530pub fn setreuid(ruid: u32, euid: u32) -> usize {530pub 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}
533533
534pub fn setregid(rgid: u32, egid: u32) -> usize {534pub 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}
537537
538pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {538pub 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}
541541
542pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {542pub 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};
653653
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
676pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {654pub 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}
679657
680pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {658pub 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}
683661
684pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize {662pub 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}
687665
688pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) -> usize {666pub 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}
691669
692pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) -> usize {670pub 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}
695673
696pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) -> usize {674pub 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}
699677
700pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {678pub 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}
703681
704pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) -> usize {682pub 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}
707685
708pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,686pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
709 noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize687 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}
713691
714pub fn shutdown(fd: i32, how: i32) -> usize {692pub 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}
717695
718pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {696pub 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}
721699
722pub fn listen(fd: i32, backlog: i32) -> usize {700pub 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}
725703
726pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) -> usize {704pub 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}
729707
730pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> usize {708pub 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}
733711
734pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {712pub 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}
737715
738pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) -> usize {716pub 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}
741719
742// error NameTooLong;720// error NameTooLong;
...@@ -771,7 +749,7 @@ pub const Stat = arch.Stat;...@@ -771,7 +749,7 @@ pub const Stat = arch.Stat;
771pub const timespec = arch.timespec;749pub const timespec = arch.timespec;
772750
773pub fn fstat(fd: i32, stat_buf: &Stat) -> usize {751pub 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}
776754
777pub const epoll_data = u64;755pub 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};
783761
784pub fn epoll_create() -> usize {762pub 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}
787765
788pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) -> usize {766pub 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}
791769
792pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: i32, timeout: i32) -> usize {770pub 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}
795773
796pub fn timerfd_create(clockid: i32, flags: u32) -> usize {774pub 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}
799777
800pub const itimerspec = extern struct {778pub const itimerspec = extern struct {
...@@ -803,11 +781,11 @@ pub const itimerspec = extern struct {...@@ -803,11 +781,11 @@ pub const itimerspec = extern struct {
803};781};
804782
805pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) -> usize {783pub 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}
808786
809pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) -> usize {787pub 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}
812790
813test "import linux_test" {791test "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
506export 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;
371pub const F_GETOWNER_UIDS = 17;371pub const F_GETOWNER_UIDS = 17;
372372
373pub fn syscall0(number: usize) -> usize {373pub 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}
379379
380pub fn syscall1(number: usize, arg1: usize) -> usize {380pub 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}
387387
388pub fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize {388pub 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}
396396
397pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {397pub 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}
406406
407pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize {407pub 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}
417417
418pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize {418pub 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}
429429
430pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize,430pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
431 arg5: usize, arg6: usize) -> usize431 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}
444444
445pub nakedcc fn restore_rt() {445pub 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}
451451
452452
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);
751751
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 true756 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 true761 true
763 }762 else
764 } else {763 unreachable;
765 unreachable764
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 {
964962
965 // windows returns \\?\ prepended to the path963 // windows returns \\?\ prepended to the path
966 // we strip it because nobody wants \\?\ prepended to their path964 // 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 };
976976
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);
10131013
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);
10161016
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.
123pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 {123pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 {
124 // count bytes needed124 // count bytes needed
125 const bytes_needed = {125 const bytes_needed = x: {
126 var bytes_needed: usize = 1; // 1 for the final null byte126 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 byte130 // +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_needed133 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 {
2828
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 }
3535
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 start84 break :x start;
85 } else {85 } else x: {
86 // Can't overflow because the range is over signed ints86 // 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.0115 // 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 16777216118 16777216
119 } else if (T == f64) {119 else if (T == f64)
120 9007199254740992120 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) -> type134 comptime l: math.Log2Int(int), comptime f: int) -> type
135{135{
136 struct {136 return struct {
137 const Self = this;137 const Self = this;
138138
139 array: [n]int,139 array: [n]int,
...@@ -189,7 +189,7 @@ fn MersenneTwister(...@@ -189,7 +189,7 @@ fn MersenneTwister(
189189
190 return x;190 return x;
191 }191 }
192 }192 };
193}193}
194194
195test "rand float 32" {195test "rand float 32" {
std/sort.zig+1022-50
...@@ -1,75 +1,966 @@...@@ -1,75 +1,966 @@
1const assert = @import("debug.zig").assert;1const std = @import("index.zig");
2const mem = @import("mem.zig");2const assert = std.debug.assert;
3const math = @import("math/index.zig");3const mem = std.mem;
4const math = std.math;
5const builtin = @import("builtin");
46
5pub 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).
68pub 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) {
8pub 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}
1818
19/// Unstable sort using O(n) stack space. Currently implemented as quicksort.19const Range = struct {
20pub 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
33const 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
94const 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.
103pub 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}
25710
26fn 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;712fn 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
30732
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
754fn 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
781fn 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
790fn 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;804fn 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}
46817
47 if (left < j) quicksort(T, array, left, j, cmp);818fn 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}
50831
51pub fn i32asc(a: &const i32, b: &const i32) -> Cmp {832fn 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.Equal833 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}
54845
55pub fn i32desc(a: &const i32, b: &const i32) -> Cmp {846fn 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}
58863
59pub fn u8asc(a: &const u8, b: &const u8) -> Cmp {864fn 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.Equal865 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}
62881
63pub fn u8desc(a: &const u8, b: &const u8) -> Cmp {882fn 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}
66911
67fn reverse(was: Cmp) -> Cmp {912fn 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.Equal913 // 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
940fn 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
949fn i32asc(lhs: &const i32, rhs: &const i32) -> bool {
950 return *lhs < *rhs;
69}951}
70952
71// ---------------------------------------953fn i32desc(lhs: &const i32, rhs: &const i32) -> bool {
72// tests954 return *rhs < *lhs;
955}
956
957fn u8asc(lhs: &const u8, rhs: &const u8) -> bool {
958 return *lhs < *rhs;
959}
960
961fn u8desc(lhs: &const u8, rhs: &const u8) -> bool {
962 return *rhs < *lhs;
963}
73964
74test "stable sort" {965test "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}
123const IdAndValue = struct {1014const IdAndValue = struct {
124 id: i32,1015 id: usize,
125 value: i32,1016 value: i32,
126};1017};
127fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> Cmp {1018fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> bool {
128 return i32asc(a.value, b.value);1019 return i32asc(a.value, b.value);
129}1020}
1301021
131test "testSort" {1022test "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}
1661062
167test "testSortDesc" {1063test "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
1087test "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
1099test "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
1113var fixed_buffer_mem: [100 * 1024]u8 = undefined;
1114
1115fn 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
1136pub 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
1147pub 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");
5const std = @import("std");5const std = @import("std");
6const builtin = @import("builtin");6const builtin = @import("builtin");
77
8const is_windows = builtin.os == builtin.Os.windows;
9const want_main_symbol = builtin.link_libc;
10const want_start_symbol = !want_main_symbol and !is_windows;
11const want_WinMainCRTStartup = is_windows and !builtin.link_libc;
12
13var argc_ptr: &usize = undefined;8var argc_ptr: &usize = undefined;
149
1510comptime {
16export 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}
2120
21nakedcc 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}
3335
34export fn WinMainCRTStartup() -> noreturn {36extern fn WinMainCRTStartup() -> noreturn {
35 if (!want_WinMainCRTStartup) {
36 @setGlobalLinkage(WinMainCRTStartup, builtin.GlobalLinkage.Internal);
37 unreachable;
38 }
39 @setAlignStack(16);37 @setAlignStack(16);
4038
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];
6057
61 std.debug.user_main_fn = root.main;
62
63 return root.main();58 return root.main();
64}59}
6560
66export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {61extern 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 @@
22
3const std = @import("std");3const std = @import("std");
44
5export stdcallcc fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD,5comptime {
6 @export("_DllMainCRTStartup", _DllMainCRTStartup);
7}
8
9stdcallcc fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD,
6 lpReserved: std.os.windows.LPVOID) -> std.os.windows.BOOL10 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 {
4545
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.stream50 break :x &stderr_file_stream.stream;
51 } else |err| {51 } else |err| err;
52 err
53 };
5452
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.stream57 break :x &stdout_file_stream.stream;
60 } else |err| {58 } else |err| err;
61 err
62 };
6359
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}
3737
38export fn __stack_chk_fail() -> noreturn {38comptime {
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}
43extern fn __stack_chk_fail() -> noreturn {
43 @panic("stack smashing detected");44 @panic("stack smashing detected");
44}45}
4546
46const math = @import("../math/index.zig");47const math = @import("../math/index.zig");
4748
48export fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) }49export fn fmodf(x: f32, y: f32) -> f32 { return generic_fmod(f32, x, y); }
49export fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) }50export fn fmod(x: f64, y: f64) -> f64 { return generic_fmod(f64, x, y); }
5051
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 @rem53// and have the math stuff use the intrinsic. same as @mod and @rem
53export fn floorf(x: f32) -> f32 { math.floor(x) }54export fn floorf(x: f32) -> f32 { return math.floor(x); }
54export fn ceilf(x: f32) -> f32 { math.ceil(x) }55export fn ceilf(x: f32) -> f32 { return math.ceil(x); }
55export fn floor(x: f64) -> f64 { math.floor(x) }56export fn floor(x: f64) -> f64 { return math.floor(x); }
56export fn ceil(x: f64) -> f64 { math.ceil(x) }57export fn ceil(x: f64) -> f64 { return math.ceil(x); }
5758
58fn generic_fmod(comptime T: type, x: T, y: T) -> T {59fn 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 y84 // 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;}) {}
118119
119 // scale result up120 // 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 @@
1const builtin = @import("builtin");1pub nakedcc fn _aulldiv() {
2const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;2 @setDebugSafety(this, false);
3const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386;3 asm volatile (
44 \\.intel_syntax noprefix
5export 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 noprefix10 \\ jne L1
11 \\11 \\ mov ecx,dword ptr [esp+14h]
12 \\ push ebx12 \\ mov eax,dword ptr [esp+10h]
13 \\ push esi13 \\ xor edx,edx
14 \\ mov eax,dword ptr [esp+18h]14 \\ div ecx
15 \\ or eax,eax15 \\ mov ebx,eax
16 \\ jne L116 \\ 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,edx19 \\ jmp L2
20 \\ div ecx20 \\ L1:
21 \\ mov ebx,eax21 \\ mov ecx,eax
22 \\ mov eax,dword ptr [esp+0Ch]22 \\ mov ebx,dword ptr [esp+14h]
23 \\ div ecx23 \\ mov edx,dword ptr [esp+10h]
24 \\ mov edx,ebx24 \\ mov eax,dword ptr [esp+0Ch]
25 \\ jmp L225 \\ L3:
26 \\ L1:26 \\ shr ecx,1
27 \\ mov ecx,eax27 \\ 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,132 \\ div ebx
33 \\ rcr ebx,133 \\ mov esi,eax
34 \\ shr edx,134 \\ mul dword ptr [esp+18h]
35 \\ rcr eax,135 \\ mov ecx,eax
36 \\ or ecx,ecx36 \\ mov eax,dword ptr [esp+14h]
37 \\ jne L337 \\ mul esi
38 \\ div ebx38 \\ add edx,ecx
39 \\ mov esi,eax39 \\ jb L4
40 \\ mul dword ptr [esp+18h]40 \\ cmp edx,dword ptr [esp+10h]
41 \\ mov ecx,eax41 \\ ja L4
42 \\ mov eax,dword ptr [esp+14h]42 \\ jb L5
43 \\ mul esi43 \\ cmp eax,dword ptr [esp+0Ch]
44 \\ add edx,ecx44 \\ jbe L5
45 \\ jb L445 \\ L4:
46 \\ cmp edx,dword ptr [esp+10h]46 \\ dec esi
47 \\ ja L447 \\ L5:
48 \\ jb L548 \\ xor edx,edx
49 \\ cmp eax,dword ptr [esp+0Ch]49 \\ mov eax,esi
50 \\ jbe L550 \\ L2:
51 \\ L4:51 \\ pop esi
52 \\ dec esi52 \\ pop ebx
53 \\ L5:53 \\ ret 10h
54 \\ xor edx,edx54 );
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 @@
1const builtin = @import("builtin");1pub nakedcc fn _aullrem() {
2const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;2 @setDebugSafety(this, false);
3const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386;3 asm volatile (
44 \\.intel_syntax noprefix
5export 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 noprefix10 \\ mov ecx,dword ptr [esp+10h]
11 \\11 \\ mov eax,dword ptr [esp+0Ch]
12 \\ push ebx12 \\ xor edx,edx
13 \\ mov eax,dword ptr [esp+14h]13 \\ div ecx
14 \\ or eax,eax14 \\ mov eax,dword ptr [esp+8]
15 \\ jne L1a15 \\ 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,edx18 \\ jmp L2a
19 \\ div ecx19 \\ L1a:
20 \\ mov eax,dword ptr [esp+8]20 \\ mov ecx,eax
21 \\ div ecx21 \\ mov ebx,dword ptr [esp+10h]
22 \\ mov eax,edx22 \\ mov edx,dword ptr [esp+0Ch]
23 \\ xor edx,edx23 \\ mov eax,dword ptr [esp+8]
24 \\ jmp L2a24 \\ L3a:
25 \\ L1a:25 \\ shr ecx,1
26 \\ mov ecx,eax26 \\ 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,131 \\ div ebx
32 \\ rcr ebx,132 \\ mov ecx,eax
33 \\ shr edx,133 \\ mul dword ptr [esp+14h]
34 \\ rcr eax,134 \\ xchg eax,ecx
35 \\ or ecx,ecx35 \\ mul dword ptr [esp+10h]
36 \\ jne L3a36 \\ add edx,ecx
37 \\ div ebx37 \\ jb L4a
38 \\ mov ecx,eax38 \\ cmp edx,dword ptr [esp+0Ch]
39 \\ mul dword ptr [esp+14h]39 \\ ja L4a
40 \\ xchg eax,ecx40 \\ jb L5a
41 \\ mul dword ptr [esp+10h]41 \\ cmp eax,dword ptr [esp+8]
42 \\ add edx,ecx42 \\ jbe L5a
43 \\ jb L4a43 \\ L4a:
44 \\ cmp edx,dword ptr [esp+0Ch]44 \\ sub eax,dword ptr [esp+10h]
45 \\ ja L4a45 \\ sbb edx,dword ptr [esp+14h]
46 \\ jb L5a46 \\ L5a:
47 \\ cmp eax,dword ptr [esp+8]47 \\ sub eax,dword ptr [esp+8]
48 \\ jbe L5a48 \\ 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 edx55 );
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;
2020
21const builtin = @import("builtin");21const builtin = @import("builtin");
22const is_test = builtin.is_test;22const is_test = builtin.is_test;
23const linkage = @import("index.zig").linkage;
2423
25export fn __letf2(a: f128, b: f128) -> c_int {24pub extern fn __letf2(a: f128, b: f128) -> c_int {
26 @setDebugSafety(this, is_test);25 @setDebugSafety(this, is_test);
27 @setGlobalLinkage(__letf2, linkage);
2826
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 {
4038
41 // If at least one of a and b is positive, we get the same result comparing39 // 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_LESS43 LE_LESS
46 } else if (aInt == bInt) {44 else if (aInt == bInt)
47 LE_EQUAL45 LE_EQUAL
48 } else {46 else
49 LE_GREATER47 LE_GREATER
50 }48 else
51 } else {
52 // Otherwise, both are negative, so we need to flip the sense of the49 // 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 a51 // 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_LESS54 LE_LESS
58 } else if (aInt == bInt) {55 else if (aInt == bInt)
59 LE_EQUAL56 LE_EQUAL
60 } else {57 else
61 LE_GREATER58 LE_GREATER
62 }59 ;
63 };
64}
65
66// Alias for libgcc compatibility
67// TODO https://github.com/zig-lang/zig/issues/420
68export fn __cmptf2(a: f128, b: f128) -> c_int {
69 @setGlobalLinkage(__cmptf2, linkage);
70 @setDebugSafety(this, is_test);
71 return __letf2(a, b);
72}60}
7361
74// TODO https://github.com/zig-lang/zig/issues/30562// 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);
78const GE_GREATER = c_int(1);66const GE_GREATER = c_int(1);
79const GE_UNORDERED = c_int(-1); // Note: different from LE_UNORDERED67const GE_UNORDERED = c_int(-1); // Note: different from LE_UNORDERED
8068
81export fn __getf2(a: f128, b: f128) -> c_int {69pub extern fn __getf2(a: f128, b: f128) -> c_int {
82 @setGlobalLinkage(__getf2, linkage);
83 @setDebugSafety(this, is_test);70 @setDebugSafety(this, is_test);
8471
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 {
8976
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_LESS81 GE_LESS
95 } else if (aInt == bInt) {82 else if (aInt == bInt)
96 GE_EQUAL83 GE_EQUAL
97 } else {84 else
98 GE_GREATER85 GE_GREATER
99 }86 else
100 } else {87 if (aInt > bInt)
101 if (aInt > bInt) {
102 GE_LESS88 GE_LESS
103 } else if (aInt == bInt) {89 else if (aInt == bInt)
104 GE_EQUAL90 GE_EQUAL
105 } else {91 else
106 GE_GREATER92 GE_GREATER
107 }93 ;
108 };
109}94}
11095
111export fn __unordtf2(a: f128, b: f128) -> c_int {96pub extern fn __unordtf2(a: f128, b: f128) -> c_int {
112 @setGlobalLinkage(__unordtf2, linkage);
113 @setDebugSafety(this, is_test);97 @setDebugSafety(this, is_test);
11498
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
123export fn __eqtf2(a: f128, b: f128) -> c_int {
124 @setGlobalLinkage(__eqtf2, linkage);
125 @setDebugSafety(this, is_test);
126 return __letf2(a, b);
127}
128
129export fn __lttf2(a: f128, b: f128) -> c_int {
130 @setGlobalLinkage(__lttf2, linkage);
131 @setDebugSafety(this, is_test);
132 return __letf2(a, b);
133}
134
135export fn __netf2(a: f128, b: f128) -> c_int {
136 @setGlobalLinkage(__netf2, linkage);
137 @setDebugSafety(this, is_test);
138 return __letf2(a, b);
139}
140
141export 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 @@
1const fixuint = @import("fixuint.zig").fixuint;1const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunsdfdi(a: f64) -> u64 {4pub 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}
108
std/special/compiler_rt/fixunsdfsi.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1const fixuint = @import("fixuint.zig").fixuint;1const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunsdfsi(a: f64) -> u32 {4pub 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}
108
std/special/compiler_rt/fixunsdfti.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1const fixuint = @import("fixuint.zig").fixuint;1const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunsdfti(a: f64) -> u128 {4pub 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}
108
std/special/compiler_rt/fixunssfdi.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1const fixuint = @import("fixuint.zig").fixuint;1const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunssfdi(a: f32) -> u64 {4pub 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}
108
std/special/compiler_rt/fixunssfsi.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1const fixuint = @import("fixuint.zig").fixuint;1const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunssfsi(a: f32) -> u32 {4pub 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}
108
std/special/compiler_rt/fixunssfti.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1const fixuint = @import("fixuint.zig").fixuint;1const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunssfti(a: f32) -> u128 {4pub 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}
108
std/special/compiler_rt/fixunstfdi.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1const fixuint = @import("fixuint.zig").fixuint;1const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunstfdi(a: f128) -> u64 {4pub 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}
108
std/special/compiler_rt/fixunstfsi.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1const fixuint = @import("fixuint.zig").fixuint;1const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunstfsi(a: f128) -> u32 {4pub 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}
108
std/special/compiler_rt/fixunstfti.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1const fixuint = @import("fixuint.zig").fixuint;1const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunstfti(a: f128) -> u128 {4pub 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}
108
std/special/compiler_rt/index.zig+165-176
...@@ -1,33 +1,74 @@...@@ -1,33 +1,74 @@
1comptime {
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
20const builtin = @import("builtin");1const builtin = @import("builtin");
21const is_test = builtin.is_test;2const is_test = builtin.is_test;
22const assert = @import("../../debug.zig").assert;
233
4comptime {
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);
2436
25const win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386;37 @export("__udivti3", @import("udivti3.zig").__udivti3, linkage);
26const win64 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.x86_64;38 @export("__umodti3", @import("umodti3.zig").__umodti3, linkage);
27const win32_nocrt = win32 and !builtin.link_libc;39
28const win64_nocrt = win64 and !builtin.link_libc;40 @export("__udivsi3", __udivsi3, linkage);
29pub const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;41 @export("__udivdi3", __udivdi3, linkage);
30const 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
71const assert = @import("../../debug.zig").assert;
3172
32const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;73const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
3374
...@@ -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}
4384
44export fn __udivdi3(a: u64, b: u64) -> u64 {85extern 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}
4989
50export fn __umoddi3(a: u64, b: u64) -> u64 {90extern fn __umoddi3(a: u64, b: u64) -> u64 {
51 @setDebugSafety(this, is_test);91 @setDebugSafety(this, is_test);
52 @setGlobalLinkage(__umoddi3, linkage);
5392
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};
63export fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult {102extern 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}
75108
76fn isArmArch() -> bool {109fn isArmArch() -> bool {
...@@ -115,156 +148,124 @@ fn isArmArch() -> bool {...@@ -115,156 +148,124 @@ fn isArmArch() -> bool {
115 };148 };
116}149}
117150
118export nakedcc fn __aeabi_uidivmod() {151nakedcc fn __aeabi_uidivmod() {
119 @setDebugSafety(this, false);152 @setDebugSafety(this, false);
120153 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, #4158 \\ ldr r1, [sp]
126 \\ mov r2, sp159 \\ add sp, sp, #4
127 \\ bl __udivmodsi4160 \\ 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}
137163
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 specific166// This routine is windows specific
141// http://msdn.microsoft.com/en-us/library/ms648426.aspx167// http://msdn.microsoft.com/en-us/library/ms648426.aspx
142export nakedcc fn _chkstk() align(4) {168nakedcc fn _chkstk() align(4) {
143 @setDebugSafety(this, false);169 @setDebugSafety(this, false);
144170
145 if (win32_nocrt) {171 asm volatile (
146 @setGlobalLinkage(_chkstk, strong_linkage);172 \\ push %%ecx
147 asm volatile (173 \\ push %%eax
148 \\ push %%ecx174 \\ cmp $0x1000,%%eax
149 \\ push %%eax175 \\ lea 12(%%esp),%%ecx
150 \\ cmp $0x1000,%%eax176 \\ jb 1f
151 \\ lea 12(%%esp),%%ecx177 \\ 2:
152 \\ jb 1f178 \\ sub $0x1000,%%ecx
153 \\ 2:179 \\ test %%ecx,(%%ecx)
154 \\ sub $0x1000,%%ecx180 \\ sub $0x1000,%%eax
155 \\ test %%ecx,(%%ecx)181 \\ cmp $0x1000,%%eax
156 \\ sub $0x1000,%%eax182 \\ ja 2b
157 \\ cmp $0x1000,%%eax183 \\ 1:
158 \\ ja 2b184 \\ sub %%eax,%%ecx
159 \\ 1:185 \\ test %%ecx,(%%ecx)
160 \\ sub %%eax,%%ecx186 \\ pop %%eax
161 \\ test %%ecx,(%%ecx)187 \\ pop %%ecx
162 \\ pop %%eax188 \\ ret
163 \\ pop %%ecx189 );
164 \\ ret
165 );
166 unreachable;
167 }
168
169 @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal);
170}190}
171191
172export nakedcc fn __chkstk() align(4) {192nakedcc fn __chkstk() align(4) {
173 @setDebugSafety(this, false);193 @setDebugSafety(this, false);
174194
175 if (win64_nocrt) {195 asm volatile (
176 @setGlobalLinkage(__chkstk, strong_linkage);196 \\ push %%rcx
177 asm volatile (197 \\ push %%rax
178 \\ push %%rcx198 \\ cmp $0x1000,%%rax
179 \\ push %%rax199 \\ lea 24(%%rsp),%%rcx
180 \\ cmp $0x1000,%%rax200 \\ jb 1f
181 \\ lea 24(%%rsp),%%rcx201 \\2:
182 \\ jb 1f202 \\ sub $0x1000,%%rcx
183 \\2:203 \\ test %%rcx,(%%rcx)
184 \\ sub $0x1000,%%rcx204 \\ sub $0x1000,%%rax
185 \\ test %%rcx,(%%rcx)205 \\ cmp $0x1000,%%rax
186 \\ sub $0x1000,%%rax206 \\ ja 2b
187 \\ cmp $0x1000,%%rax207 \\1:
188 \\ ja 2b208 \\ sub %%rax,%%rcx
189 \\1:209 \\ test %%rcx,(%%rcx)
190 \\ sub %%rax,%%rcx210 \\ pop %%rax
191 \\ test %%rcx,(%%rcx)211 \\ pop %%rcx
192 \\ pop %%rax212 \\ ret
193 \\ pop %%rcx213 );
194 \\ ret
195 );
196 unreachable;
197 }
198
199 @setGlobalLinkage(__chkstk, builtin.GlobalLinkage.Internal);
200}214}
201215
202// _chkstk routine216// _chkstk routine
203// This routine is windows specific217// This routine is windows specific
204// http://msdn.microsoft.com/en-us/library/ms648426.aspx218// http://msdn.microsoft.com/en-us/library/ms648426.aspx
205export nakedcc fn __chkstk_ms() align(4) {219nakedcc fn __chkstk_ms() align(4) {
206 @setDebugSafety(this, false);220 @setDebugSafety(this, false);
207221
208 if (win32_nocrt) {222 asm volatile (
209 @setGlobalLinkage(__chkstk_ms, linkage);223 \\ push %%ecx
210 asm volatile (224 \\ push %%eax
211 \\ push %%ecx225 \\ cmp $0x1000,%%eax
212 \\ push %%eax226 \\ lea 12(%%esp),%%ecx
213 \\ cmp $0x1000,%%eax227 \\ jb 1f
214 \\ lea 12(%%esp),%%ecx228 \\ 2:
215 \\ jb 1f229 \\ sub $0x1000,%%ecx
216 \\ 2:230 \\ test %%ecx,(%%ecx)
217 \\ sub $0x1000,%%ecx231 \\ sub $0x1000,%%eax
218 \\ test %%ecx,(%%ecx)232 \\ cmp $0x1000,%%eax
219 \\ sub $0x1000,%%eax233 \\ ja 2b
220 \\ cmp $0x1000,%%eax234 \\ 1:
221 \\ ja 2b235 \\ sub %%eax,%%ecx
222 \\ 1:236 \\ test %%ecx,(%%ecx)
223 \\ sub %%eax,%%ecx237 \\ pop %%eax
224 \\ test %%ecx,(%%ecx)238 \\ pop %%ecx
225 \\ pop %%eax239 \\ ret
226 \\ pop %%ecx240 );
227 \\ ret
228 );
229 unreachable;
230 }
231
232 @setGlobalLinkage(__chkstk_ms, builtin.GlobalLinkage.Internal);
233}241}
234242
235export nakedcc fn ___chkstk_ms() align(4) {243nakedcc fn ___chkstk_ms() align(4) {
236 @setDebugSafety(this, false);244 @setDebugSafety(this, false);
237245
238 if (win64_nocrt) {246 asm volatile (
239 @setGlobalLinkage(___chkstk_ms, linkage);247 \\ push %%rcx
240 asm volatile (248 \\ push %%rax
241 \\ push %%rcx249 \\ cmp $0x1000,%%rax
242 \\ push %%rax250 \\ lea 24(%%rsp),%%rcx
243 \\ cmp $0x1000,%%rax251 \\ jb 1f
244 \\ lea 24(%%rsp),%%rcx252 \\2:
245 \\ jb 1f253 \\ sub $0x1000,%%rcx
246 \\2:254 \\ test %%rcx,(%%rcx)
247 \\ sub $0x1000,%%rcx255 \\ sub $0x1000,%%rax
248 \\ test %%rcx,(%%rcx)256 \\ cmp $0x1000,%%rax
249 \\ sub $0x1000,%%rax257 \\ ja 2b
250 \\ cmp $0x1000,%%rax258 \\1:
251 \\ ja 2b259 \\ sub %%rax,%%rcx
252 \\1:260 \\ test %%rcx,(%%rcx)
253 \\ sub %%rax,%%rcx261 \\ pop %%rax
254 \\ test %%rcx,(%%rcx)262 \\ pop %%rcx
255 \\ pop %%rax263 \\ ret
256 \\ pop %%rcx264 );
257 \\ ret
258 );
259 unreachable;
260 }
261
262 @setGlobalLinkage(___chkstk_ms, builtin.GlobalLinkage.Internal);
263}265}
264266
265export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 {267extern fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 {
266 @setDebugSafety(this, is_test);268 @setDebugSafety(this, is_test);
267 @setGlobalLinkage(__udivmodsi4, linkage);
268269
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}
273274
274275
275// TODO make this an alias instead of an extra function call276extern fn __udivsi3(n: u32, d: u32) -> u32 {
276// https://github.com/andrewrk/zig/issues/256
277
278export 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
285export fn __udivsi3(n: u32, d: u32) -> u32 {
286 @setDebugSafety(this, is_test);
287 @setGlobalLinkage(__udivsi3, linkage);
288278
289 const n_uword_bits: c_uint = u32.bit_count;279 const n_uword_bits: c_uint = u32.bit_count;
290 // special cases280 // 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 @@
1const udivmod = @import("udivmod.zig").udivmod;1const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) -> u64 {4pub 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}
108
std/special/compiler_rt/udivmodti4.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1const udivmod = @import("udivmod.zig").udivmod;1const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) -> u128 {4pub 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}
108
std/special/compiler_rt/udivti3.zig+1-3
...@@ -1,9 +1,7 @@...@@ -1,9 +1,7 @@
1const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;1const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __udivti3(a: u128, b: u128) -> u128 {4pub 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 @@
1const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;1const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __umodti3(a: u128, b: u128) -> u128 {4pub 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}
1212
13fn derp() align(@sizeOf(usize) * 2) -> i32 { 1234 }13fn derp() align(@sizeOf(usize) * 2) -> i32 { return 1234; }
14fn noop1() align(1) {}14fn noop1() align(1) {}
15fn noop4() align(4) {}15fn noop4() align(4) {}
1616
...@@ -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}
5555
56fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) -> u32 { *a + *b }56fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) -> u32 { return *a + *b; }
5757
58test "implicitly decreasing slice alignment" {58test "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}
63fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) -> u32 { a[0] + b[0] }63fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) -> u32 { return a[0] + b[0]; }
6464
65test "specifying alignment allows pointer cast" {65test "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}
117117
118fn alignedSmall() align(8) -> i32 { 1234 }118fn alignedSmall() align(8) -> i32 { return 1234; }
119fn alignedBig() align(16) -> i32 { 5678 }119fn alignedBig() align(16) -> i32 { return 5678; }
120120
121121
122test "@alignCast functions" {122test "@alignCast functions" {
123 assert(fnExpectsOnly1(simple4) == 0x19);123 assert(fnExpectsOnly1(simple4) == 0x19);
124}124}
125fn fnExpectsOnly1(ptr: fn()align(1) -> i32) -> i32 {125fn fnExpectsOnly1(ptr: fn()align(1) -> i32) -> i32 {
126 fnExpects4(@alignCast(4, ptr))126 return fnExpects4(@alignCast(4, ptr));
127}127}
128fn fnExpects4(ptr: fn()align(4) -> i32) -> i32 {128fn fnExpects4(ptr: fn()align(4) -> i32) -> i32 {
129 ptr()129 return ptr();
130}130}
131fn simple4() align(4) -> i32 { 0x19 }131fn simple4() align(4) -> i32 { return 0x19; }
132132
133133
134test "generic function with align param" {134test "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}
139139
140fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) -> u8 { 0x1 }140fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) -> u8 { return 0x1; }
141141
142142
143test "@ptrCast preserves alignment of bigger source" {143test "@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}
24fn getArrayLen(a: []const u32) -> usize {24fn getArrayLen(a: []const u32) -> usize {
25 a.len25 return a.len;
26}26}
2727
28test "void arrays" {28test "void arrays" {
...@@ -41,7 +41,7 @@ test "array literal" {...@@ -41,7 +41,7 @@ test "array literal" {
41}41}
4242
43test "array dot len const expr" {43test "array dot len const expr" {
44 assert(comptime {some_array.len == 4});44 assert(comptime x: {break :x some_array.len == 4;});
45}45}
4646
47const ArrayDotLenConstExpr = struct {47const 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}
1212
13fn conv(x: i32) -> u32 { @bitCast(u32, x) }13fn conv(x: i32) -> u32 { return @bitCast(u32, x); }
14fn conv2(x: u32) -> i32 { @bitCast(i32, x) }14fn 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}
24fn testBoolCmp(a: bool, b: bool) -> bool {24fn testBoolCmp(a: bool, b: bool) -> bool {
25 a == b25 return a == b;
26}26}
2727
28const global_f = false;28const global_f = false;
test/cases/bugs/655.zig created+12
...@@ -0,0 +1,12 @@
1const std = @import("std");
2const other_file = @import("655_other_file.zig");
3
4test "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
10fn 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 @@
1pub const Integer = u32;
test/cases/bugs/656.zig created+30
...@@ -0,0 +1,30 @@
1const assert = @import("std").debug.assert;
2
3const PrefixOp = union(enum) {
4 Return,
5 AddrOf: Value,
6};
7
8const Value = struct {
9 align_expr: ?u32,
10};
11
12test "nullable if after an if in a switch prong of a switch with 2 prongs in an else" {
13 foo(false, true);
14}
15
16fn 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}
52fn boolToStr(b: bool) -> []const u8 {52fn boolToStr(b: bool) -> []const u8 {
53 if (b) "true" else "false"53 return if (b) "true" else "false";
54}54}
5555
5656
...@@ -239,17 +239,17 @@ test "peer type resolution: error and [N]T" {...@@ -239,17 +239,17 @@ test "peer type resolution: error and [N]T" {
239239
240error BadValue;240error BadValue;
241fn testPeerErrorAndArray(x: u8) -> %[]const u8 {241fn 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}
247fn testPeerErrorAndArray2(x: u8) -> %[]const u8 {247fn 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}
254254
255test "explicit cast float number literal to integer if no fraction component" {255test "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}
270270
271fn cast128Int(x: f128) -> u128 {271fn cast128Int(x: f128) -> u128 {
272 @bitCast(u128, x)272 return @bitCast(u128, x);
273}273}
274274
275fn cast128Float(x: u128) -> f128 {275fn cast128Float(x: u128) -> f128 {
276 @bitCast(f128, x)276 return @bitCast(f128, x);
277}277}
278278
279test "const slice widen cast" {279test "const slice widen cast" {
test/cases/defer.zig+6-6
...@@ -7,9 +7,9 @@ error FalseNotAllowed;...@@ -7,9 +7,9 @@ error FalseNotAllowed;
77
8fn runSomeErrorDefers(x: bool) -> %bool {8fn 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}
1515
...@@ -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');
2020
21 const ok = runSomeErrorDefers(false) %% |err| {21 const ok = runSomeErrorDefers(false) %% |err| x: {
22 assert(err == error.FalseNotAllowed);22 assert(err == error.FalseNotAllowed);
23 true23 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};
4242
43fn returnAnInt(x: i32) -> Foo {43fn returnAnInt(x: i32) -> Foo {
44 Foo { .One = x }44 return Foo { .One = x };
45}45}
4646
4747
...@@ -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
348test "cast integer literal to enum" {
349 assert(MultipleChoice2(0) == MultipleChoice2.Unspecified1);
350 assert(MultipleChoice2(40) == MultipleChoice2.B);
351}
352
353const EnumWithOneMember = enum {
354 Eof,
355};
356
357fn 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
366test "comparison operator on enum with one member is comptime known" {
367 doALoopThing(EnumWithOneMember.Eof);
368}
369
370const State = enum {
371 Start,
372};
373test "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) {
88
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};
1616
test/cases/error.zig+5-9
...@@ -3,7 +3,7 @@ const mem = @import("std").mem;...@@ -3,7 +3,7 @@ const mem = @import("std").mem;
33
4pub fn foo() -> %i32 {4pub fn foo() -> %i32 {
5 const x = %return bar();5 const x = %return bar();
6 return x + 16 return x + 1;
7}7}
88
9pub fn bar() -> %i32 {9pub fn bar() -> %i32 {
...@@ -21,7 +21,7 @@ test "error wrapping" {...@@ -21,7 +21,7 @@ test "error wrapping" {
2121
22error ItBroke;22error ItBroke;
23fn gimmeItBroke() -> []const u8 {23fn gimmeItBroke() -> []const u8 {
24 @errorName(error.ItBroke)24 return @errorName(error.ItBroke);
25}25}
2626
27test "@errorName" {27test "@errorName" {
...@@ -48,7 +48,7 @@ error AnError;...@@ -48,7 +48,7 @@ error AnError;
48error AnError;48error AnError;
49error SecondError;49error SecondError;
50fn shouldBeNotEqual(a: error, b: error) {50fn shouldBeNotEqual(a: error, b: error) {
51 if (a == b) unreachable51 if (a == b) unreachable;
52}52}
5353
5454
...@@ -60,11 +60,7 @@ test "error binary operator" {...@@ -60,11 +60,7 @@ test "error binary operator" {
60}60}
61error ItBroke;61error ItBroke;
62fn errBinaryOperatorG(x: bool) -> %isize {62fn 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}
6965
7066
...@@ -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}
75fn unwrapSimpleValueFromErrorDo() -> %isize { 13 }71fn unwrapSimpleValueFromErrorDo() -> %isize { return 13; }
7672
7773
78test "error return in assignment" {74test "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}
46const statically_added_number = staticAdd(1, 2);46const statically_added_number = staticAdd(1, 2);
47fn staticAdd(a: i32, b: i32) -> i32 { a + b }47fn staticAdd(a: i32, b: i32) -> i32 { return a + b; }
4848
4949
50test "const expr eval on single expr blocks" {50test "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" {
54fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) -> i32 {54fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) -> i32 {
55 const literal = 3;55 const literal = 3;
5656
57 const result = if (b) {57 const result = if (b) b: {
58 literal58 break :b literal;
59 } else {59 } else b: {
60 x60 break :b x;
61 };61 };
6262
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};
96pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 {96pub 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}
101101
102102
...@@ -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}
178fn letsTryToCompareBools(a: bool, b: bool) -> bool {178fn letsTryToCompareBools(a: bool, b: bool) -> bool {
179 max(bool, a, b)179 return max(bool, a, b);
180}180}
181test "inlined block and runtime block phi" {181test "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};
205fn one(value: i32) -> i32 { value + 1 }205fn one(value: i32) -> i32 { return value + 1; }
206fn two(value: i32) -> i32 { value + 2 }206fn two(value: i32) -> i32 { return value + 2; }
207fn three(value: i32) -> i32 { value + 3 }207fn three(value: i32) -> i32 { return value + 3; }
208208
209fn performFn(comptime prefix_char: u8, start_value: i32) -> i32 {209fn 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}
319319
320const global_array = {320const 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 result325 break :x result;
326};326};
327327
328test "compile-time downcast when the bits fit" {328test "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}
6fn testParamsAdd(a: i32, b: i32) -> i32 {6fn testParamsAdd(a: i32, b: i32) -> i32 {
7 a + b7 return a + b;
8}8}
99
1010
...@@ -22,7 +22,7 @@ test "void parameters" {...@@ -22,7 +22,7 @@ test "void parameters" {
22}22}
23fn voidFun(a: i32, b: void, c: i32, d: void) {23fn 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 }
4747
48 const c = {48 const c = x: {
49 const no_conflict = i32(10);49 const no_conflict = i32(10);
50 no_conflict50 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" {
73fn wantsFnWithVoid(f: fn()) { }73fn wantsFnWithVoid(f: fn()) { }
7474
75fn fnWithUnreachable() -> noreturn {75fn fnWithUnreachable() -> noreturn {
76 unreachable76 unreachable;
77}77}
7878
7979
...@@ -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}
86fn fn1() -> u32 {5}86fn fn1() -> u32 {return 5;}
87fn fn2() -> u32 {6}87fn fn2() -> u32 {return 6;}
88fn fn3() -> u32 {7}88fn fn3() -> u32 {return 7;}
89fn fn4() -> u32 {8}89fn fn4() -> u32 {return 8;}
9090
9191
92test "inline function call" {92test "inline function call" {
93 assert(@inlineCall(add, 3, 9) == 12);93 assert(@inlineCall(add, 3, 9) == 12);
94}94}
9595
96fn add(a: i32, b: i32) -> i32 { a + b }96fn 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) unreachable15 if (sum != 6) unreachable;
16}16}
1717
18test "for loop with pointer elem var" {18test "for loop with pointer elem var" {
...@@ -55,3 +55,37 @@ test "basic for loop" {...@@ -55,3 +55,37 @@ test "basic for loop" {
5555
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
59test "break from outer for loop" {
60 testBreakOuter();
61 comptime testBreakOuter();
62}
63
64fn 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
76test "continue outer for loop" {
77 testContinueOuter();
78 comptime testContinueOuter();
79}
80
81fn 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}
1212
13fn add(comptime a: i32, b: i32) -> i32 {13fn add(comptime a: i32, b: i32) -> i32 {
14 return (comptime {a}) + b;14 return (comptime a) + b;
15}15}
1616
17const the_max = max(u32, 1234, 5678);17const 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}
2121
22fn gimmeTheBigOne(a: u32, b: u32) -> u32 {22fn gimmeTheBigOne(a: u32, b: u32) -> u32 {
23 max(u32, a, b)23 return max(u32, a, b);
24}24}
2525
26fn shouldCallSameInstance(a: u32, b: u32) -> u32 {26fn shouldCallSameInstance(a: u32, b: u32) -> u32 {
27 max(u32, a, b)27 return max(u32, a, b);
28}28}
2929
30fn sameButWithFloats(a: f64, b: f64) -> f64 {30fn sameButWithFloats(a: f64, b: f64) -> f64 {
31 max(f64, a, b)31 return max(f64, a, b);
32}32}
3333
34test "fn with comptime args" {34test "fn with comptime args" {
...@@ -49,28 +49,28 @@ comptime {...@@ -49,28 +49,28 @@ comptime {
49}49}
5050
51fn max_var(a: var, b: var) -> @typeOf(a + b) {51fn max_var(a: var, b: var) -> @typeOf(a + b) {
52 if (a > b) a else b52 return if (a > b) a else b;
53}53}
5454
55fn max_i32(a: i32, b: i32) -> i32 {55fn max_i32(a: i32, b: i32) -> i32 {
56 max_var(a, b)56 return max_var(a, b);
57}57}
5858
59fn max_f64(a: f64, b: f64) -> f64 {59fn max_f64(a: f64, b: f64) -> f64 {
60 max_var(a, b)60 return max_var(a, b);
61}61}
6262
6363
64pub fn List(comptime T: type) -> type {64pub fn List(comptime T: type) -> type {
65 SmallList(T, 8)65 return SmallList(T, 8);
66}66}
6767
68pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {68pub 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}
7575
76test "function with return type type" {76test "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}
93fn GenNode(comptime T: type) -> type {93fn 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}
100100
101test "const decls in struct" {101test "const decls in struct" {
102 assert(GenericDataThing(3).count_plus_one == 4);102 assert(GenericDataThing(3).count_plus_one == 4);
103}103}
104fn GenericDataThing(comptime count: isize) -> type {104fn 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}
109109
110110
...@@ -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}
123fn getByte(ptr: ?&const u8) -> u8 {*??ptr}123fn getByte(ptr: ?&const u8) -> u8 {return *??ptr;}
124fn getFirstByte(comptime T: type, mem: []const T) -> u8 {124fn 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}
127127
128128
129const foos = []fn(var) -> bool { foo1, foo2 };129const foos = []fn(var) -> bool { foo1, foo2 };
130130
131fn foo1(arg: var) -> bool { arg }131fn foo1(arg: var) -> bool { return arg; }
132fn foo2(arg: var) -> bool { !arg }132fn foo2(arg: var) -> bool { return !arg; }
133133
134test "array of generic fns" {134test "array of generic fns" {
135 assert(foos[0](true));135 assert(foos[0](true));
test/cases/goto.zig deleted-37
...@@ -1,37 +0,0 @@
1const assert = @import("std").debug.assert;
2
3test "goto and labels" {
4 gotoLoop();
5 assert(goto_counter == 10);
6}
7fn gotoLoop() {
8 var i: i32 = 0;
9 goto cond;
10loop:
11 i += 1;
12cond:
13 if (!(i < 10)) goto end;
14 goto_counter += 1;
15 goto loop;
16end:
17}
18var goto_counter: i32 = 0;
19
20
21
22test "goto leave defer scope" {
23 testGotoLeaveDeferScope(true);
24}
25fn testGotoLeaveDeferScope(b: bool) {
26 var it_worked = false;
27
28 goto entry;
29exit:
30 if (it_worked) {
31 return;
32 }
33 unreachable;
34entry:
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}
30fn elseIfExpressionF(c: u8) -> u8 {30fn elseIfExpressionF(c: u8) -> u8 {
31 if (c == 0) {31 if (c == 0) {
32 032 return 0;
33 } else if (c == 1) {33 } else if (c == 1) {
34 134 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 @@
1pub fn foo() -> i32 { 1234 }1pub 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}
1313
14fn getErrInt() -> %i32 { 0 }14fn getErrInt() -> %i32 { return 0; }
1515
16error ItBroke;16error ItBroke;
1717
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}
30fn div(comptime T: type, a: T, b: T) -> T {30fn div(comptime T: type, a: T, b: T) -> T {
31 a / b31 return a / b;
32}32}
33fn divExact(comptime T: type, a: T, b: T) -> T {33fn divExact(comptime T: type, a: T, b: T) -> T {
34 @divExact(a, b)34 return @divExact(a, b);
35}35}
36fn divFloor(comptime T: type, a: T, b: T) -> T {36fn divFloor(comptime T: type, a: T, b: T) -> T {
37 @divFloor(a, b)37 return @divFloor(a, b);
38}38}
39fn divTrunc(comptime T: type, a: T, b: T) -> T {39fn divTrunc(comptime T: type, a: T, b: T) -> T {
40 @divTrunc(a, b)40 return @divTrunc(a, b);
41}41}
4242
43test "@addWithOverflow" {43test "@addWithOverflow" {
...@@ -71,7 +71,7 @@ fn testClz() {...@@ -71,7 +71,7 @@ fn testClz() {
71}71}
7272
73fn clz(x: var) -> usize {73fn clz(x: var) -> usize {
74 @clz(x)74 return @clz(x);
75}75}
7676
77test "@ctz" {77test "@ctz" {
...@@ -86,7 +86,7 @@ fn testCtz() {...@@ -86,7 +86,7 @@ fn testCtz() {
86}86}
8787
88fn ctz(x: var) -> usize {88fn ctz(x: var) -> usize {
89 @ctz(x)89 return @ctz(x);
90}90}
9191
92test "assignment operators" {92test "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}
182fn divWithResult(a: u64, b: u64) -> DivResult {182fn 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}
188const DivResult = struct {188const DivResult = struct {
189 quotient: u64,189 quotient: u64,
...@@ -191,8 +191,8 @@ const DivResult = struct {...@@ -191,8 +191,8 @@ const DivResult = struct {
191};191};
192192
193test "binary not" {193test "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}
198198
...@@ -331,7 +331,7 @@ test "f128" {...@@ -331,7 +331,7 @@ test "f128" {
331 comptime test_f128();331 comptime test_f128();
332}332}
333333
334fn make_f128(x: f128) -> f128 { x }334fn make_f128(x: f128) -> f128 { return x; }
335335
336fn test_f128() {336fn 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}
1414
15export fn disabledExternFn() {15comptime {
16 @setGlobalLinkage(disabledExternFn, builtin.GlobalLinkage.Internal);16 @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
17}
18
19extern fn disabledExternFn() {
17}20}
1821
19test "call disabled extern fn" {22test "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;
109112
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 }
116119
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}
134fn testTruncate(x: u32) -> u8 {137fn testTruncate(x: u32) -> u8 {
135 @truncate(u8, x)138 return @truncate(u8, x);
136}139}
137140
138fn first4KeysOfHomeRow() -> []const u8 {141fn first4KeysOfHomeRow() -> []const u8 {
139 "aoeu"142 return "aoeu";
140}143}
141144
142test "return string from function" {145test "return string from function" {
...@@ -164,7 +167,7 @@ test "memcpy and memset intrinsics" {...@@ -164,7 +167,7 @@ test "memcpy and memset intrinsics" {
164}167}
165168
166test "builtin static eval" {169test "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}
170173
...@@ -187,7 +190,7 @@ test "slicing" {...@@ -187,7 +190,7 @@ test "slicing" {
187190
188test "constant equal function pointers" {191test "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}
192195
193fn emptyFn() {}196fn 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}
280fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { x }283fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { return x; }
281fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { x }284fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { return x; }
282285
283286
284test "implicit cast after unreachable" {287test "implicit cast after unreachable" {
285 assert(outer() == 1234);288 assert(outer() == 1234);
286}289}
287fn inner() -> i32 { 1234 }290fn inner() -> i32 { return 1234; }
288fn outer() -> i64 {291fn 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" {
307fn f2(x: bool) -> []const u8 {310fn f2(x: bool) -> []const u8 {
308 return (if (x) fA else fB)();311 return (if (x) fA else fB)();
309}312}
310fn fA() -> []const u8 { "a" }313fn fA() -> []const u8 { return "a"; }
311fn fB() -> []const u8 { "b" }314fn fB() -> []const u8 { return "b"; }
312315
313316
314test "const expression eval handling of variables" {317test "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}
378fn ptrEql(a: &const []const u8, b: &const []const u8) -> bool {381fn ptrEql(a: &const []const u8, b: &const []const u8) -> bool {
379 a == b382 return a == b;
380}383}
381384
382385
...@@ -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 fn487 // TODO bound fn
485 // TODO arg tuple488 // TODO arg tuple
486 // TODO opaque489 // TODO opaque
...@@ -504,7 +507,7 @@ test "@typeName" {...@@ -504,7 +507,7 @@ test "@typeName" {
504507
505test "volatile load and store" {508test "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}
2424
25fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }25fn dummy(a: bool, b: i32, c: f32) -> i32 { return 1234; }
26fn dummy_varargs(args: ...) {}26fn dummy_varargs(args: ...) {}
2727
28test "reflection: struct member types and names" {28test "reflection: struct member types and names" {
test/cases/slice.zig+19
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
2const mem = @import("std").mem;
23
3const x = @intToPtr(&i32, 0x1000)[0..0x500];4const x = @intToPtr(&i32, 0x1000)[0..0x500];
4const y = x[0x100..];5const 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
20test "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
25fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) -> []u8 {
26 return a_slice[start..end];
27}
28
29test "implicitly cast array of size 0 to slice" {
30 var msg = []u8 {};
31 assertLenIsZero(msg);
32}
33
34fn 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;
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4const StructWithNoFields = struct {4const 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};
7const empty_global_instance = StructWithNoFields {};7const empty_global_instance = StructWithNoFields {};
88
...@@ -109,7 +109,7 @@ const Foo = struct {...@@ -109,7 +109,7 @@ const Foo = struct {
109 ptr: fn() -> i32,109 ptr: fn() -> i32,
110};110};
111111
112fn aFunc() -> i32 { 13 }112fn aFunc() -> i32 { return 13; }
113113
114fn callStructField(foo: &const Foo) -> i32 {114fn 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}
125const MemberFnTestFoo = struct {125const 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};
129129
130130
...@@ -141,7 +141,7 @@ test "member functions" {...@@ -141,7 +141,7 @@ test "member functions" {
141const MemberFnRand = struct {141const 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.seed144 return r.seed;
145 }145 }
146};146};
147147
...@@ -154,10 +154,10 @@ const Bar = struct {...@@ -154,10 +154,10 @@ const Bar = struct {
154 y: i32,154 y: i32,
155};155};
156fn makeBar(x: i32, y: i32) -> Bar {156fn 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}
162162
163test "empty struct method call" {163test "empty struct method call" {
...@@ -166,7 +166,7 @@ test "empty struct method call" {...@@ -166,7 +166,7 @@ test "empty struct method call" {
166}166}
167const EmptyStruct = struct {167const EmptyStruct = struct {
168 fn method(es: &const EmptyStruct) -> i32 {168 fn method(es: &const EmptyStruct) -> i32 {
169 1234169 return 1234;
170 }170 }
171};171};
172172
...@@ -176,14 +176,14 @@ test "return empty struct from fn" {...@@ -176,14 +176,14 @@ test "return empty struct from fn" {
176}176}
177const EmptyStruct2 = struct {};177const EmptyStruct2 = struct {};
178fn testReturnEmptyStructFromFn() -> EmptyStruct2 {178fn testReturnEmptyStructFromFn() -> EmptyStruct2 {
179 EmptyStruct2 {}179 return EmptyStruct2 {};
180}180}
181181
182test "pass slice of empty struct to fn" {182test "pass slice of empty struct to fn" {
183 assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1);183 assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1);
184}184}
185fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) -> usize {185fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) -> usize {
186 slice.len186 return slice.len;
187}187}
188188
189const APackedStruct = packed struct {189const 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
383const 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
393test "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}
2222
23fn testSwitchWithAllRanges(x: u32, y: u32) -> u32 {23fn 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}
3131
32test "implicit comptime switch" {32test "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}
134fn returnsFive() -> i32 {134fn returnsFive() -> i32 {
135 5135 return 5;
136}136}
137137
138138
...@@ -161,10 +161,10 @@ test "switch on type" {...@@ -161,10 +161,10 @@ test "switch on type" {
161}161}
162162
163fn trueIfBoolFalseOtherwise(comptime T: type) -> bool {163fn 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}
169169
170test "switch handles all cases of number" {170test "switch handles all cases of number" {
...@@ -186,22 +186,22 @@ fn testSwitchHandleAllCases() {...@@ -186,22 +186,22 @@ fn testSwitchHandleAllCases() {
186}186}
187187
188fn testSwitchHandleAllCasesExhaustive(x: u2) -> u2 {188fn 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}
196196
197fn testSwitchHandleAllCasesRange(x: u8) -> u8 {197fn 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}
206206
207test "switch all prongs unreachable" {207test "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}
2323
24test "switch prong returns error enum" {24test "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) {
8error Whatever;8error Whatever;
99
10fn foo(id: u64) -> %FormValue {10fn 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}
1717
18test "switch prong implicit cast" {18test "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;
3const module = this;3const module = this;
44
5fn Point(comptime T: type) -> type {5fn 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}
1717
18fn add(x: i32, y: i32) -> i32 {18fn add(x: i32, y: i32) -> i32 {
19 x + y19 return x + y;
20}20}
2121
22fn factorial(x: i32) -> i32 {22fn 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}
3026
31test "this refer to module call private fn" {27test "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}
88
9fn tryOnErrorUnionImpl() {9fn tryOnErrorUnionImpl() {
10 const x = if (returnsTen()) |val| {10 const x = if (returnsTen()) |val|
11 val + 111 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;
21error NoMem;21error NoMem;
22error CrappedOut;22error CrappedOut;
23fn returnsTen() -> %i32 {23fn returnsTen() -> %i32 {
24 1024 return 10;
25}25}
2626
27test "try without vars" {27test "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);
3430
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}
4234
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" {
190fn testCastUnionToTagType(x: &const TheUnion) {190fn testCastUnionToTagType(x: &const TheUnion) {
191 assert(TheTag(*x) == TheTag.B);191 assert(TheTag(*x) == TheTag.B);
192}192}
193
194test "cast tag type of union to union" {
195 var x: Value2 = Letter2.B;
196 assert(Letter2(x) == Letter2.B);
197}
198const Letter2 = enum { A, B, C };
199const Value2 = union(Letter2) { A: i32, B, C, };
200
201test "implicit cast union to its tag type" {
202 var x: Value2 = Letter2.B;
203 assert(x == Letter2.B);
204 giveMeLetterB(x);
205}
206fn giveMeLetterB(x: Letter2) {
207 assert(x == Value2.B);
208}
209
210test "implicit cast from @EnumTagType(TheUnion) to &const TheUnion" {
211 assertIsTheUnion2Item1(TheUnion2.Item1);
212}
213
214const TheUnion2 = union(enum) {
215 Item1,
216 Item2: i32,
217};
218
219fn 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 {
5858
59const foos = []fn(...) -> bool { foo1, foo2 };59const foos = []fn(...) -> bool { foo1, foo2 };
6060
61fn foo1(args: ...) -> bool { true }61fn foo1(args: ...) -> bool { return true; }
62fn foo2(args: ...) -> bool { false }62fn foo2(args: ...) -> bool { return false; }
6363
64test "array of var args functions" {64test "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" {
118var numbers_left: i32 = undefined;118var numbers_left: i32 = undefined;
119error OutOfNumbers;119error OutOfNumbers;
120fn getNumberOrErr() -> %i32 {120fn getNumberOrErr() -> %i32 {
121 return if (numbers_left == 0) {121 return if (numbers_left == 0)
122 error.OutOfNumbers122 error.OutOfNumbers
123 } else {123 else x: {
124 numbers_left -= 1;124 numbers_left -= 1;
125 numbers_left125 break :x numbers_left;
126 };126 };
127}127}
128fn getNumberOrNull() -> ?i32 {128fn getNumberOrNull() -> ?i32 {
129 return if (numbers_left == 0) {129 return if (numbers_left == 0)
130 null130 null
131 } else {131 else x: {
132 numbers_left -= 1;132 numbers_left -= 1;
133 numbers_left133 break :x numbers_left;
134 };134 };
135}135}
136136
137test "while on nullable with else result follow else prong" {137test "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}
145143
146test "while on nullable with else result follow break prong" {144test "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}
154150
155test "while on error union with else result follow else prong" {151test "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}
163157
164test "while on error union with else result follow break prong" {158test "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}
172164
173test "while on bool with else result follow else prong" {165test "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}
181171
182test "while on bool with else result follow break prong" {172test "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}
190178
191fn returnNull() -> ?i32 { null }179test "break from outer while loop" {
192fn returnMaybe(x: i32) -> ?i32 { x }180 testBreakOuter();
181 comptime testBreakOuter();
182}
183
184fn testBreakOuter() {
185 outer: while (true) {
186 while (true) {
187 break :outer;
188 }
189 }
190}
191
192test "continue outer while loop" {
193 testContinueOuter();
194 comptime testContinueOuter();
195}
196
197fn testContinueOuter() {
198 var i: usize = 0;
199 outer: while (i < 10) : (i += 1) {
200 while (true) {
201 continue :outer;
202 }
203 }
204}
205
206fn returnNull() -> ?i32 { return null; }
207fn returnMaybe(x: i32) -> ?i32 { return x; }
193error YouWantedAnError;208error YouWantedAnError;
194fn returnError() -> %i32 { error.YouWantedAnError }209fn returnError() -> %i32 { return error.YouWantedAnError; }
195fn returnSuccess(x: i32) -> %i32 { x }210fn returnSuccess(x: i32) -> %i32 { return x; }
196fn returnFalse() -> bool { false }211fn returnFalse() -> bool { return false; }
197fn returnTrue() -> bool { true }212fn 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);
1212
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 );
4343
44 tc44 break :x tc;
45 });45 });
4646
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 );
8484
85 tc85 break :x tc;
86 });86 });
8787
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 );
114114
115 tc115 break :x tc;
116 });116 });
117117
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 \\ -1289 \\ return -1;
290 \\ } else if (*a_int > *b_int) {290 \\ } else if (*a_int > *b_int) {
291 \\ 1291 \\ 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");
431431
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) {
442442
443 tc.addSourceFile("foo.txt", "1234\nabcd\n");443 tc.addSourceFile("foo.txt", "1234\nabcd\n");
444444
445 tc445 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 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) {3pub 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'");
1243
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'");
2152
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'");
3061
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'");
3970
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'");
5788
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'");
6697
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'");
75106
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'");
84115
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'");
93124
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'");
102133
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'");
111142
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'");
120151
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'");
129160
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'");
138169
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'");
147178
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'");
156187
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'");
165196
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'");
174205
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'");
183214
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'");
192223
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) {
245276
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 \\ c281 \\ 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'");
254286
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 \\ a310 \\ 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'");
281313
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) {
362394
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'");
371403
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");
376408
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");
383415
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) {
476508
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");
483515
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) {
502534
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");
507539
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");
550582
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");
571603
...@@ -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");
593625
...@@ -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");
616648
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'");
641673
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");
647679
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'");
655687
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");
663695
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");
669701
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)'");
676708
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'");
681713
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)'");
686718
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");
712744
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");
720752
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'");
728760
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'");
737769
738770
...@@ -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'");
745777
746778
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) {
755787
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 '");
760792
761793
...@@ -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");
774806
...@@ -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'");
784816
785817
...@@ -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 = "a836 \\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");
809841
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()'");
816848
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");
825857
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)'");
851863
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 / x874 \\ 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");
869881
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");
875887
876888
...@@ -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'");
893905
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");
903915
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) {
928940
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 == b943 \\ 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 == *b950 \\ 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'");
946958
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 \\ 2968 \\ 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");
959971
...@@ -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 \\ -x991 \\ 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");
986998
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 + b1002 \\ 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");
9971009
9981010
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 - b1014 \\ 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");
10091021
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 * b1025 \\ 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");
10201032
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'");
10291041
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) {
10561068
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 + y1071 \\ 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'");
10621074
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'");
10701082
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'");
11071119
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");
11181130
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");
11431155
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'");
11761188
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)'");
12291241
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 );
12441256
1245 tc1257 break :x tc;
1246 });1258 });
12471259
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'");
12541266
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");
12821294
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");
12961308
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");
13121324
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) {
13181330
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");
13231335
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");
13281340
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'");
13631375
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");
13991411
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");
14061418
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");
14301442
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");
14371449
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'");
14481460
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'");
14611473
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");
14721484
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 );
14771489
1478 tc1490 break :x tc;
1479 });1491 });
14801492
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");
14861498
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'");
15091521
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");
16131625
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");
16221633
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'");
16311649
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) {
16481666
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'");
16801698
...@@ -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'");
16881706
...@@ -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'");
16961714
...@@ -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'");
17041722
...@@ -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'");
17121730
...@@ -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'");
17201738
...@@ -1745,17 +1763,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1745,17 +1763,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
17451763
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 / b1766 \\ 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");
17521770
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 % b1773 \\ 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");
17591777
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");
18401858
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) {
19151923
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'");
19221930
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'");
19291937
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) {
20212029
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'");
20392047
...@@ -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'");
21222130
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'");
21292138
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 + b37 \\ return a + b;
38 \\}38 \\}
39 );39 );
4040
...@@ -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 - b51 \\ return a - b;
52 \\}52 \\}
53 );53 );
5454
...@@ -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 * b65 \\ return a * b;
66 \\}66 \\}
67 );67 );
6868
...@@ -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 \\ -a79 \\ return -a;
80 \\}80 \\}
81 );81 );
8282
...@@ -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 );
9696
...@@ -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 );
110110
...@@ -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 );
124124
...@@ -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 );
138138
...@@ -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 );
152152
...@@ -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 );
165165
...@@ -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 );
179179
...@@ -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 );
193193
...@@ -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 );
207207
...@@ -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 );
221221
test/standalone/pkg_import/pkg.zig+1-1
...@@ -1 +1 @@...@@ -1 +1 @@
1pub fn add(a: i32, b: i32) -> i32 { a + b }1pub 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,
192193
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 };
205210
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,
213219
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) -> &RunCompareOutputStep221 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;
234242
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 }
236251
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);
238253
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();
241256
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 }
273288
274289
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 }
421437
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);
425441
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 }
448464
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);
452468
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 }
603619
604620
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 }
879895
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 );
215215
...@@ -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 \\ _tmp481 \\ 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 );
549549
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 \\ 2618 \\ 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 \\ *_ref651 \\ 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 \\ *_ref656 \\ 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 \\ *_ref661 \\ 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 \\ *_ref666 \\ 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 \\ *_ref671 \\ 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 \\ *_ref676 \\ 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 \\ *_ref681 \\ 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 \\ *_ref686 \\ 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 \\ *_ref709 \\ 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 \\ *_ref714 \\ 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 \\ *_ref719 \\ 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 \\ *_ref724 \\ 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 \\ *_ref729 \\ 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 \\ *_ref734 \\ 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 \\ *_ref739 \\ 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 \\ *_ref744 \\ 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 \\ _tmp785 \\ 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 \\ _tmp791 \\ 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 \\ _tmp797 \\ 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 \\ _tmp803 \\ 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 \\ *_ref832 \\ 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 \\ *_ref837 \\ 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 \\ *_ref842 \\ 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 \\ *_ref847 \\ 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 );
908908
...@@ -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 );
936936
...@@ -1005,48 +1005,6 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -1005,48 +1005,6 @@ pub fn addCases(cases: &tests.TranslateCContext) {
1005 \\}1005 \\}
1006 );1006 );
10071007
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 );
10871045
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}