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.
119119[![Build Status](https://travis-ci.org/zig-lang/zig.svg?branch=master)](https://travis-ci.org/zig-lang/zig)
120120[![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### Dependencies
122### Stage 1: Build Zig from C++ Source Code
123123
124#### Build Dependencies
125
126These compile tools must be available on your system and are used to build
127the Zig compiler itself:
124#### Dependencies
128125
129126##### POSIX
130127
131128 * gcc >= 5.0.0 or clang >= 3.6.0
132129 * cmake >= 2.8.5
130 * LLVM, Clang, LLD libraries == 6.x, compiled with the same gcc or clang version above
133131
134132##### Windows
135133
136134 * Microsoft Visual Studio 2015
135 * LLVM, Clang, LLD libraries == 6.x, compiled with the same MSVC version above
137136
138#### Library Dependencies
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
137#### Instructions
147138
148139If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`,
149140`ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to
......@@ -158,7 +149,7 @@ make install
158149./zig build --build-file ../build.zig test
159150```
160151
161#### MacOS
152##### MacOS
162153
163154`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused.
164155
......@@ -172,21 +163,35 @@ make install
172163./zig build --build-file ../build.zig test
173164```
174165
175#### Windows
166##### Windows
176167
177168See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows
178169
179### Release / Install Build
170### Stage 2: Build Self-Hosted Zig from Zig Source Code
180171
181Once installed, `ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_INCLUDE_DIR` can be overridden
182by the `--libc-lib-dir` and `--libc-include-dir` parameters to the zig binary.
172*Note: Stage 2 compiler is not complete. Beta users of Zig should use the
173Stage 1 compiler for now.*
174
175Dependencies are the same as Stage 1, except now you have a working zig compiler.
183176
184177```
185mkdir build
186cd build
187cmake .. -DCMAKE_BUILD_TYPE=Release -DZIG_LIBC_LIB_DIR=/some/path -DZIG_LIBC_INCLUDE_DIR=/some/path -DZIG_LIBC_STATIC_INCLUDE_DIR=/some/path
188make
189sudo make install
178bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install
179```
180
181### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler
182
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
190195```
191196
192197### Test Coverage
build.zig+218-8
......@@ -1,6 +1,13 @@
1const Builder = @import("std").build.Builder;
1const std = @import("std");
2const Builder = std.build.Builder;
23const 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
512pub fn build(b: &Builder) {
613 const mode = b.standardReleaseOptions();
......@@ -25,14 +32,18 @@ pub fn build(b: &Builder) {
2532 docs_step.dependOn(&docgen_cmd.step);
2633 docs_step.dependOn(&docgen_home_cmd.step);
2734
28 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
29 exe.setBuildMode(mode);
30 exe.linkSystemLibrary("c");
35 if (findLLVM(b)) |llvm| {
36 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
37 exe.setBuildMode(mode);
38 exe.linkSystemLibrary("c");
39 dependOnLib(exe, llvm);
3140
32 b.default_step.dependOn(&exe.step);
33 b.default_step.dependOn(docs_step);
41 b.default_step.dependOn(&exe.step);
42 b.default_step.dependOn(docs_step);
3443
35 b.installArtifact(exe);
44 b.installArtifact(exe);
45 installStdLib(b);
46 }
3647
3748
3849 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) {
5364 "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests",
5465 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
5671 test_step.dependOn(tests.addCompareOutputTests(b, test_filter));
5772 test_step.dependOn(tests.addBuildExampleTests(b, test_filter));
5873 test_step.dependOn(tests.addCompileErrorTests(b, test_filter));
......@@ -60,3 +75,198 @@ pub fn build(b: &Builder) {
6075 test_step.dependOn(tests.addDebugSafetyTests(b, test_filter));
6176 test_step.dependOn(tests.addTranslateCTests(b, test_filter));
6277}
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 {
4242
4343// TODO look for code segments
4444
45fn gen(in: &io.InStream, out: &const io.OutStream) {
45fn gen(in: &io.InStream, out: &io.OutStream) {
4646 var state = State.Start;
4747 while (true) {
4848 const byte = in.readByte() %% |err| {
4949 if (err == error.EndOfStream) {
5050 return;
5151 }
52 std.debug.panic("{}", err)
52 std.debug.panic("{}", err);
5353 };
5454 switch (state) {
5555 State.Start => switch (byte) {
doc/langref.html.in+21-20
......@@ -136,6 +136,7 @@
136136 <li><a href="#builtin-divFloor">@divFloor</a></li>
137137 <li><a href="#builtin-divTrunc">@divTrunc</a></li>
138138 <li><a href="#builtin-embedFile">@embedFile</a></li>
139 <li><a href="#builtin-export">@export</a></li>
139140 <li><a href="#builtin-tagName">@tagName</a></li>
140141 <li><a href="#builtin-EnumTagType">@EnumTagType</a></li>
141142 <li><a href="#builtin-errorName">@errorName</a></li>
......@@ -3020,14 +3021,13 @@ const assert = @import("std").debug.assert;</code></pre>
30203021 <pre><code class="zig">const assert = @import("std").debug.assert;
30213022
30223023// Functions are declared like this
3023// The last expression in the function can be used as the return value.
30243024fn add(a: i8, b: i8) -&gt; i8 {
30253025 if (a == 0) {
30263026 // You can still return manually if needed.
30273027 return b;
30283028 }
30293029
3030 a + b
3030 return a + b;
30313031}
30323032
30333033// The export specifier makes a function externally visible in the generated
......@@ -4368,6 +4368,11 @@ test.zig:6:2: error: found compile log statement
43684368 <ul>
43694369 <li><a href="#builtin-import">@import</a></li>
43704370 </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>
43714376 <h3 id="builtin-tagName">@tagName</h3>
43724377 <pre><code class="zig">@tagName(value: var) -&gt; []const u8</code></pre>
43734378 <p>
......@@ -5815,13 +5820,15 @@ TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestD
58155820
58165821TestDecl = "test" String Block
58175822
5818TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
5823TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
58195824
58205825ErrorValueDecl = "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 ")") "=" Expression
5831VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression
58255832
58265833ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
58275834
......@@ -5831,21 +5838,17 @@ UseDecl = "use" Expression ";"
58315838
58325839ExternDecl = "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"
5837
5838FnDef = option("inline" | "extern") FnProto Block
5843FnDef = option("inline" | "export") FnProto Block
58395844
58405845ParamDeclList = "(" list(ParamDecl, ",") ")"
58415846
58425847ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
58435848
5844Block = "{" many(Statement) option(Expression) "}"
5845
5846Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
5849Block = option(Symbol ":") "{" many(Statement) "}"
58475850
5848Label = Symbol ":"
5851Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
58495852
58505853TypeExpr = PrefixOpExpression | "var"
58515854
......@@ -5885,13 +5888,13 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=&gt;" option("|" option("*") Sy
58855888
58865889SwitchItem = 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
58905893BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
58915894
58925895ReturnExpression = option("%") "return" option(Expression)
58935896
5894BreakExpression = "break" option(Expression)
5897BreakExpression = "break" option(":" Symbol) option(Expression)
58955898
58965899Defer(body) = option("%") "defer" body
58975900
......@@ -5901,7 +5904,7 @@ TryExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|")
59015904
59025905TestExpression(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
59065909BoolAndExpression = ComparisonExpression "and" BoolAndExpression | ComparisonExpression
59075910
......@@ -5949,15 +5952,13 @@ StructLiteralField = "." Symbol "=" Expression
59495952
59505953PrefixOp = "!" | "-" | "~" | "*" | ("&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) | ContainerDecl
5955PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol))
59535956
59545957ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
59555958
5956GotoExpression = "goto" Symbol
5957
59585959GroupedExpression = "(" Expression ")"
59595960
5960KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
5961KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
59615962
59625963ContainerDecl = option("extern" | "packed")
59635964 ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))
example/shared_library/mathtest.zig+1-1
......@@ -1,3 +1,3 @@
11export fn add(a: i32, b: i32) -> i32 {
2 a + b
2 return a + b;
33}
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 @@
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;
113const builtin = @import("builtin");
2const io = @import("std").io;
3const os = @import("std").os;
4const heap = @import("std").heap;
14const ArrayList = std.ArrayList;
515
6// TODO: sync up CLI with c++ code
7// TODO: concurrency
16error InvalidCommandLineArguments;
17error ZigLibDirNotFound;
18error ZigInstallationNotFound;
819
9error InvalidArgument;
10error MissingArg0;
11
12var arg0: []u8 = undefined;
13
14var stderr_file: io.File = undefined;
15const stderr = &stderr_file.out_stream;
20const default_zig_cache_name = "zig-cache";
1621
1722pub fn main() -> %void {
18 stderr_file = %return io.getStdErr();
19 if (internal_main()) |_| {
20 return;
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;
23 main2() %% |err| {
24 if (err != error.InvalidCommandLineArguments) {
25 warn("{}\n", @errorName(err));
2726 }
2827 return err;
29 }
28 };
3029}
3130
32pub fn internal_main() -> %void {
33 var args_it = os.args();
31const Cmd = enum {
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| {
36 io.stderr.printf("Unable to allocate memory") %% {};
37 return err;
38 };
39 defer incrementing_allocator.deinit();
41fn badArgs(comptime format: []const u8, args: ...) -> error {
42 var stderr = %return io.getStdErr();
43 var stderr_stream_adapter = io.FileOutStream.init(&stderr);
44 const stderr_stream = &stderr_stream_adapter.stream;
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;
42
43 arg0 = %return (args_it.next(allocator) ?? error.MissingArg0);
44 defer allocator.free(arg0);
56 var cmd = Cmd.None;
57 var build_kind: Module.Kind = undefined;
58 var build_mode: builtin.Mode = builtin.Mode.Debug;
59 var color = ErrColor.Auto;
60 var emit_file_type = Emit.Binary;
4561
46 var build_mode = builtin.Mode.Debug;
4762 var strip = false;
4863 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;
5067 var verbose_link = false;
5168 var verbose_ir = false;
69 var verbose_llvm_ir = false;
70 var verbose_cimport = false;
5271 var mwindows = false;
5372 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| {
56 const arg = %return arg_or_err;
103 var clang_argv = ArrayList([]const u8).init(allocator);
104 defer clang_argv.deinit();
57105
58 if (arg[0] == '-') {
59 if (strcmp(arg, "--release-fast") == 0) {
106 var llvm_argv = ArrayList([]const u8).init(allocator);
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")) {
60134 build_mode = builtin.Mode.ReleaseFast;
61 } else if (strcmp(arg, "--release-safe") == 0) {
135 } else if (mem.eql(u8, arg, "--release-safe")) {
62136 build_mode = builtin.Mode.ReleaseSafe;
63 } else if (strcmp(arg, "--strip") == 0) {
137 } else if (mem.eql(u8, arg, "--strip")) {
64138 strip = true;
65 } else if (strcmp(arg, "--static") == 0) {
139 } else if (mem.eql(u8, arg, "--static")) {
66140 is_static = true;
67 } else if (strcmp(arg, "--verbose") == 0) {
68 verbose = true;
69 } else if (strcmp(arg, "--verbose-link") == 0) {
141 } else if (mem.eql(u8, arg, "--verbose-tokenize")) {
142 verbose_tokenize = true;
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")) {
70148 verbose_link = true;
71 } else if (strcmp(arg, "--verbose-ir") == 0) {
149 } else if (mem.eql(u8, arg, "--verbose-ir")) {
72150 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")) {
74156 mwindows = true;
75 } else if (strcmp(arg, "-mconsole") == 0) {
157 } else if (mem.eql(u8, arg, "-mconsole")) {
76158 mconsole = true;
77 } else if (strcmp(arg, "-municode") == 0) {
78 municode = true;
79 } else if (strcmp(arg, "-rdynamic") == 0) {
159 } else if (mem.eql(u8, arg, "-rdynamic")) {
80160 rdynamic = true;
81 } else if (strcmp(arg, "--each-lib-rpath") == 0) {
161 } else if (mem.eql(u8, arg, "--each-lib-rpath")) {
82162 each_lib_rpath = true;
83 } else if (strcmp(arg, "--enable-timing-info") == 0) {
163 } else if (mem.eql(u8, arg, "--enable-timing-info")) {
84164 timing_info = true;
85 } else if (strcmp(arg, "--test-cmd-bin") == 0) {
86 test_exec_args.append(nullptr);
87 } else if (arg[1] == 'L' && arg[2] != 0) {
165 } else if (mem.eql(u8, arg, "--test-cmd-bin")) {
166 @panic("TODO --test-cmd-bin");
167 } else if (arg[1] == 'L' and arg.len > 2) {
88168 // alias for --library-path
89 lib_dirs.append(&arg[2]);
90 } else if (strcmp(arg, "--pkg-begin") == 0) {
91 if (i + 2 >= argc) {
92 fprintf(stderr, "Expected 2 arguments after --pkg-begin\n");
93 return usage(arg0);
94 }
95 CliPkg *new_cur_pkg = allocate<CliPkg>(1);
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);
169 %return lib_dirs.append(arg[1..]);
170 } else if (mem.eql(u8, arg, "--pkg-begin")) {
171 @panic("TODO --pkg-begin");
172 } else if (mem.eql(u8, arg, "--pkg-end")) {
173 @panic("TODO --pkg-end");
174 } else if (arg_i + 1 >= args.len) {
175 return badArgs("expected another argument after {}", arg);
112176 } else {
113 i += 1;
114 if (strcmp(arg, "--output") == 0) {
115 out_file = argv[i];
116 } else if (strcmp(arg, "--output-h") == 0) {
117 out_file_h = argv[i];
118 } else if (strcmp(arg, "--color") == 0) {
119 if (strcmp(argv[i], "auto") == 0) {
120 color = ErrColorAuto;
121 } else if (strcmp(argv[i], "on") == 0) {
122 color = ErrColorOn;
123 } else if (strcmp(argv[i], "off") == 0) {
124 color = ErrColorOff;
177 arg_i += 1;
178 if (mem.eql(u8, arg, "--output")) {
179 out_file = args[arg_i];
180 } else if (mem.eql(u8, arg, "--output-h")) {
181 out_file_h = args[arg_i];
182 } else if (mem.eql(u8, arg, "--color")) {
183 if (mem.eql(u8, args[arg_i], "auto")) {
184 color = ErrColor.Auto;
185 } else if (mem.eql(u8, args[arg_i], "on")) {
186 color = ErrColor.On;
187 } else if (mem.eql(u8, args[arg_i], "off")) {
188 color = ErrColor.Off;
125189 } else {
126 fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n");
127 return usage(arg0);
190 return badArgs("--color options are 'auto', 'on', or 'off'");
128191 }
129 } else if (strcmp(arg, "--name") == 0) {
130 out_name = argv[i];
131 } else if (strcmp(arg, "--libc-lib-dir") == 0) {
132 libc_lib_dir = argv[i];
133 } else if (strcmp(arg, "--libc-static-lib-dir") == 0) {
134 libc_static_lib_dir = argv[i];
135 } else if (strcmp(arg, "--libc-include-dir") == 0) {
136 libc_include_dir = argv[i];
137 } else if (strcmp(arg, "--msvc-lib-dir") == 0) {
138 msvc_lib_dir = argv[i];
139 } else if (strcmp(arg, "--kernel32-lib-dir") == 0) {
140 kernel32_lib_dir = argv[i];
141 } else if (strcmp(arg, "--zig-install-prefix") == 0) {
142 zig_install_prefix = argv[i];
143 } else if (strcmp(arg, "--dynamic-linker") == 0) {
144 dynamic_linker = argv[i];
145 } else if (strcmp(arg, "-isystem") == 0) {
146 clang_argv.append("-isystem");
147 clang_argv.append(argv[i]);
148 } else if (strcmp(arg, "-dirafter") == 0) {
149 clang_argv.append("-dirafter");
150 clang_argv.append(argv[i]);
151 } else if (strcmp(arg, "-mllvm") == 0) {
152 clang_argv.append("-mllvm");
153 clang_argv.append(argv[i]);
154
155 llvm_argv.append(argv[i]);
156 } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {
157 lib_dirs.append(argv[i]);
158 } else if (strcmp(arg, "--library") == 0) {
159 link_libs.append(argv[i]);
160 } else if (strcmp(arg, "--object") == 0) {
161 objects.append(argv[i]);
162 } else if (strcmp(arg, "--assembly") == 0) {
163 asm_files.append(argv[i]);
164 } else if (strcmp(arg, "--cache-dir") == 0) {
165 cache_dir = argv[i];
166 } else if (strcmp(arg, "--target-arch") == 0) {
167 target_arch = argv[i];
168 } else if (strcmp(arg, "--target-os") == 0) {
169 target_os = argv[i];
170 } else if (strcmp(arg, "--target-environ") == 0) {
171 target_environ = argv[i];
172 } else if (strcmp(arg, "-mmacosx-version-min") == 0) {
173 mmacosx_version_min = argv[i];
174 } else if (strcmp(arg, "-mios-version-min") == 0) {
175 mios_version_min = argv[i];
176 } else if (strcmp(arg, "-framework") == 0) {
177 frameworks.append(argv[i]);
178 } else if (strcmp(arg, "--linker-script") == 0) {
179 linker_script = argv[i];
180 } else if (strcmp(arg, "-rpath") == 0) {
181 rpath_list.append(argv[i]);
182 } else if (strcmp(arg, "--test-filter") == 0) {
183 test_filter = argv[i];
184 } else if (strcmp(arg, "--test-name-prefix") == 0) {
185 test_name_prefix = argv[i];
186 } else if (strcmp(arg, "--ver-major") == 0) {
187 ver_major = atoi(argv[i]);
188 } else if (strcmp(arg, "--ver-minor") == 0) {
189 ver_minor = atoi(argv[i]);
190 } else if (strcmp(arg, "--ver-patch") == 0) {
191 ver_patch = atoi(argv[i]);
192 } else if (strcmp(arg, "--test-cmd") == 0) {
193 test_exec_args.append(argv[i]);
192 } else if (mem.eql(u8, arg, "--emit")) {
193 if (mem.eql(u8, args[arg_i], "asm")) {
194 emit_file_type = Emit.Assembly;
195 } else if (mem.eql(u8, args[arg_i], "bin")) {
196 emit_file_type = Emit.Binary;
197 } else if (mem.eql(u8, args[arg_i], "llvm-ir")) {
198 emit_file_type = Emit.LlvmIr;
199 } else {
200 return badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'");
201 }
202 } else if (mem.eql(u8, arg, "--name")) {
203 out_name_arg = args[arg_i];
204 } else if (mem.eql(u8, arg, "--libc-lib-dir")) {
205 libc_lib_dir_arg = args[arg_i];
206 } else if (mem.eql(u8, arg, "--libc-static-lib-dir")) {
207 libc_static_lib_dir_arg = args[arg_i];
208 } else if (mem.eql(u8, arg, "--libc-include-dir")) {
209 libc_include_dir_arg = args[arg_i];
210 } else if (mem.eql(u8, arg, "--msvc-lib-dir")) {
211 msvc_lib_dir_arg = args[arg_i];
212 } else if (mem.eql(u8, arg, "--kernel32-lib-dir")) {
213 kernel32_lib_dir_arg = args[arg_i];
214 } else if (mem.eql(u8, arg, "--zig-install-prefix")) {
215 zig_install_prefix = args[arg_i];
216 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
217 dynamic_linker_arg = args[arg_i];
218 } else if (mem.eql(u8, arg, "-isystem")) {
219 %return clang_argv.append("-isystem");
220 %return clang_argv.append(args[arg_i]);
221 } else if (mem.eql(u8, arg, "-dirafter")) {
222 %return clang_argv.append("-dirafter");
223 %return clang_argv.append(args[arg_i]);
224 } else if (mem.eql(u8, arg, "-mllvm")) {
225 %return clang_argv.append("-mllvm");
226 %return clang_argv.append(args[arg_i]);
227
228 %return llvm_argv.append(args[arg_i]);
229 } else if (mem.eql(u8, arg, "--library-path") or mem.eql(u8, arg, "-L")) {
230 %return lib_dirs.append(args[arg_i]);
231 } else if (mem.eql(u8, arg, "--library")) {
232 %return link_libs.append(args[arg_i]);
233 } else if (mem.eql(u8, arg, "--object")) {
234 %return objects.append(args[arg_i]);
235 } else if (mem.eql(u8, arg, "--assembly")) {
236 %return asm_files.append(args[arg_i]);
237 } else if (mem.eql(u8, arg, "--cache-dir")) {
238 cache_dir_arg = args[arg_i];
239 } else if (mem.eql(u8, arg, "--target-arch")) {
240 target_arch = args[arg_i];
241 } else if (mem.eql(u8, arg, "--target-os")) {
242 target_os = args[arg_i];
243 } else if (mem.eql(u8, arg, "--target-environ")) {
244 target_environ = args[arg_i];
245 } else if (mem.eql(u8, arg, "-mmacosx-version-min")) {
246 mmacosx_version_min = args[arg_i];
247 } else if (mem.eql(u8, arg, "-mios-version-min")) {
248 mios_version_min = args[arg_i];
249 } else if (mem.eql(u8, arg, "-framework")) {
250 %return frameworks.append(args[arg_i]);
251 } else if (mem.eql(u8, arg, "--linker-script")) {
252 linker_script_arg = args[arg_i];
253 } else if (mem.eql(u8, arg, "-rpath")) {
254 %return rpath_list.append(args[arg_i]);
255 } else if (mem.eql(u8, arg, "--test-filter")) {
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");
194267 } else {
195 fprintf(stderr, "Invalid argument: %s\n", arg);
196 return usage(arg0);
268 return badArgs("invalid argument: {}", arg);
197269 }
198270 }
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,
199305 }
200306 }
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 }
201468}
202469
203fn printUsage(outstream: &io.OutStream) -> %void {
204 %return outstream.print("Usage: {} [command] [options]\n", arg0);
205 %return outstream.write(
470fn printUsage(stream: &io.OutStream) -> %void {
471 %return stream.write(
472 \\Usage: zig [command] [options]
473 \\
206474 \\Commands:
207475 \\ build build project from build.zig
208476 \\ build-exe [source] create executable from source or object files
......@@ -217,6 +485,7 @@ fn printUsage(outstream: &io.OutStream) -> %void {
217485 \\ --assembly [source] add assembly file to build
218486 \\ --cache-dir [path] override the cache directory
219487 \\ --color [auto|off|on] enable or disable colored error messages
488 \\ --emit [filetype] emit a specific file format as compilation output
220489 \\ --enable-timing-info print timing diagnostics
221490 \\ --libc-include-dir [path] directory where libc stdlib.h resides
222491 \\ --name [name] override output name
......@@ -231,9 +500,13 @@ fn printUsage(outstream: &io.OutStream) -> %void {
231500 \\ --target-arch [name] specify target architecture
232501 \\ --target-environ [name] specify target environment
233502 \\ --target-os [name] specify target operating system
234 \\ --verbose turn on compiler debug output
235 \\ --verbose-link turn on compiler debug output for linking only
236 \\ --verbose-ir turn on compiler debug output for IR only
503 \\ --verbose-tokenize enable compiler debug info: tokenization
504 \\ --verbose-ast-tree enable compiler debug info: parsing into an AST (treeview)
505 \\ --verbose-ast-fmt enable compiler debug info: parsing into an AST (render source)
506 \\ --verbose-cimport enable compiler debug info: C imports
507 \\ --verbose-ir enable compiler debug info: Zig IR
508 \\ --verbose-llvm-ir enable compiler debug info: LLVM IR
509 \\ --verbose-link enable compiler debug info: linking
237510 \\ --zig-install-prefix [path] override directory where zig thinks it is installed
238511 \\ -dirafter [dir] same as -isystem but do it last
239512 \\ -isystem [dir] add additional search path for other .h files
......@@ -255,7 +528,6 @@ fn printUsage(outstream: &io.OutStream) -> %void {
255528 \\ -rpath [path] add directory to the runtime library search path
256529 \\ -mconsole (windows) --subsystem console to the linker
257530 \\ -mwindows (windows) --subsystem windows to the linker
258 \\ -municode (windows) link with unicode
259531 \\ -framework [name] (darwin) link against framework
260532 \\ -mios-version-min [ver] (darwin) set iOS deployment target
261533 \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target
......@@ -271,17 +543,81 @@ fn printUsage(outstream: &io.OutStream) -> %void {
271543 );
272544}
273545
274const ZIG_ZEN =
275 \\ * Communicate intent precisely.
276 \\ * Edge cases matter.
277 \\ * Favor reading code over writing code.
278 \\ * Only one obvious way to do things.
279 \\ * Runtime crashes are better than bugs.
280 \\ * Compile errors are better than runtime crashes.
281 \\ * Incremental improvements.
282 \\ * Avoid local maximums.
283 \\ * Reduce the amount one must remember.
284 \\ * Minimize energy spent on coding style.
285 \\ * Together we serve end users.
286 \\
287;
546fn printZen() -> %void {
547 var stdout_file = %return io.getStdErr();
548 %return stdout_file.write(
549 \\
550 \\ * Communicate intent precisely.
551 \\ * Edge cases matter.
552 \\ * Favor reading code over writing code.
553 \\ * Only one obvious way to do things.
554 \\ * Runtime crashes are better than bugs.
555 \\ * Compile errors are better than runtime crashes.
556 \\ * Incremental improvements.
557 \\ * Avoid local maximums.
558 \\ * Reduce the amount one must remember.
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;
2626struct TypeTableEntry;
2727struct VariableTableEntry;
2828struct ErrorTableEntry;
29struct LabelTableEntry;
3029struct BuiltinFnEntry;
3130struct TypeStructField;
3231struct CodeGen;
......@@ -37,6 +36,7 @@ struct IrBasicBlock;
3736struct ScopeDecls;
3837struct ZigWindowsSDK;
3938struct Tld;
39struct TldExport;
4040
4141struct IrGotoItem {
4242 AstNode *source_node;
......@@ -53,7 +53,6 @@ struct IrExecutable {
5353 size_t *backward_branch_count;
5454 size_t backward_branch_quota;
5555 bool invalid;
56 ZigList<LabelTableEntry *> all_labels;
5756 ZigList<IrGotoItem> goto_list;
5857 bool is_inline;
5958 FnTableEntry *fn_entry;
......@@ -272,7 +271,6 @@ enum ReturnKnowledge {
272271enum VisibMod {
273272 VisibModPrivate,
274273 VisibModPub,
275 VisibModExport,
276274};
277275
278276enum GlobalLinkageId {
......@@ -313,11 +311,8 @@ struct TldVar {
313311 Tld base;
314312
315313 VariableTableEntry *var;
316 AstNode *set_global_section_node;
317 Buf *section_name;
318 AstNode *set_global_linkage_node;
319 GlobalLinkageId linkage;
320314 Buf *extern_lib_name;
315 Buf *section_name;
321316};
322317
323318struct TldFn {
......@@ -389,8 +384,6 @@ enum NodeType {
389384 NodeTypeSwitchExpr,
390385 NodeTypeSwitchProng,
391386 NodeTypeSwitchRange,
392 NodeTypeLabel,
393 NodeTypeGoto,
394387 NodeTypeCompTime,
395388 NodeTypeBreak,
396389 NodeTypeContinue,
......@@ -425,6 +418,7 @@ struct AstNodeFnProto {
425418 AstNode *return_type;
426419 bool is_var_args;
427420 bool is_extern;
421 bool is_export;
428422 bool is_inline;
429423 CallingConvention cc;
430424 AstNode *fn_def_node;
......@@ -432,6 +426,8 @@ struct AstNodeFnProto {
432426 Buf *lib_name;
433427 // populated if the "align A" is present
434428 AstNode *align_expr;
429 // populated if the "section(S)" is present
430 AstNode *section_expr;
435431};
436432
437433struct AstNodeFnDef {
......@@ -452,8 +448,8 @@ struct AstNodeParamDecl {
452448};
453449
454450struct AstNodeBlock {
451 Buf *name;
455452 ZigList<AstNode *> statements;
456 bool last_statement_is_result_expression;
457453};
458454
459455enum ReturnKind {
......@@ -480,15 +476,18 @@ struct AstNodeVariableDeclaration {
480476 VisibMod visib_mod;
481477 Buf *symbol;
482478 bool is_const;
483 bool is_inline;
479 bool is_comptime;
480 bool is_export;
484481 bool is_extern;
485482 // one or both of type and expr will be non null
486483 AstNode *type;
487484 AstNode *expr;
488485 // populated if this is an extern declaration
489486 Buf *lib_name;
490 // populated if the "align A" is present
487 // populated if the "align(A)" is present
491488 AstNode *align_expr;
489 // populated if the "section(S)" is present
490 AstNode *section_expr;
492491};
493492
494493struct AstNodeErrorValueDecl {
......@@ -659,6 +658,7 @@ struct AstNodeTestExpr {
659658};
660659
661660struct AstNodeWhileExpr {
661 Buf *name;
662662 AstNode *condition;
663663 Buf *var_symbol;
664664 bool var_is_ptr;
......@@ -670,6 +670,7 @@ struct AstNodeWhileExpr {
670670};
671671
672672struct AstNodeForExpr {
673 Buf *name;
673674 AstNode *array_expr;
674675 AstNode *elem_node; // always a symbol
675676 AstNode *index_node; // always a symbol, might be null
......@@ -701,11 +702,6 @@ struct AstNodeLabel {
701702 Buf *name;
702703};
703704
704struct AstNodeGoto {
705 Buf *name;
706 bool is_inline;
707};
708
709705struct AstNodeCompTime {
710706 AstNode *expr;
711707};
......@@ -833,11 +829,14 @@ struct AstNodeBoolLiteral {
833829};
834830
835831struct AstNodeBreakExpr {
832 Buf *name;
836833 AstNode *expr; // may be null
837834};
838835
839836struct AstNodeContinueExpr {
837 Buf *name;
840838};
839
841840struct AstNodeUnreachableExpr {
842841};
843842
......@@ -883,7 +882,6 @@ struct AstNode {
883882 AstNodeSwitchProng switch_prong;
884883 AstNodeSwitchRange switch_range;
885884 AstNodeLabel label;
886 AstNodeGoto goto_expr;
887885 AstNodeCompTime comptime_expr;
888886 AstNodeAsmExpr asm_expr;
889887 AstNodeFieldAccessExpr field_access_expr;
......@@ -1177,6 +1175,11 @@ enum FnInline {
11771175 FnInlineNever,
11781176};
11791177
1178struct FnExport {
1179 Buf name;
1180 GlobalLinkageId linkage;
1181};
1182
11801183struct FnTableEntry {
11811184 LLVMValueRef llvm_value;
11821185 const char *llvm_name;
......@@ -1204,12 +1207,11 @@ struct FnTableEntry {
12041207 ZigList<IrInstruction *> alloca_list;
12051208 ZigList<VariableTableEntry *> variable_list;
12061209
1207 AstNode *set_global_section_node;
12081210 Buf *section_name;
1209 AstNode *set_global_linkage_node;
1210 GlobalLinkageId linkage;
12111211 AstNode *set_alignstack_node;
12121212 uint32_t alignstack_value;
1213
1214 ZigList<FnExport> export_list;
12131215};
12141216
12151217uint32_t fn_table_entry_hash(FnTableEntry*);
......@@ -1258,8 +1260,6 @@ enum BuiltinFnId {
12581260 BuiltinFnIdSetFloatMode,
12591261 BuiltinFnIdTypeName,
12601262 BuiltinFnIdCanImplicitCast,
1261 BuiltinFnIdSetGlobalSection,
1262 BuiltinFnIdSetGlobalLinkage,
12631263 BuiltinFnIdPanic,
12641264 BuiltinFnIdPtrCast,
12651265 BuiltinFnIdBitCast,
......@@ -1270,6 +1270,7 @@ enum BuiltinFnId {
12701270 BuiltinFnIdFieldParentPtr,
12711271 BuiltinFnIdOffsetOf,
12721272 BuiltinFnIdInlineCall,
1273 BuiltinFnIdNoInlineCall,
12731274 BuiltinFnIdTypeId,
12741275 BuiltinFnIdShlExact,
12751276 BuiltinFnIdShrExact,
......@@ -1278,6 +1279,7 @@ enum BuiltinFnId {
12781279 BuiltinFnIdOpaqueType,
12791280 BuiltinFnIdSetAlignStack,
12801281 BuiltinFnIdArgType,
1282 BuiltinFnIdExport,
12811283};
12821284
12831285struct BuiltinFnEntry {
......@@ -1424,7 +1426,7 @@ struct CodeGen {
14241426 HashMap<GenericFnTypeId *, FnTableEntry *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
14251427 HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
14261428 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;
14281430 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
14291431
14301432
......@@ -1439,7 +1441,7 @@ struct CodeGen {
14391441
14401442 struct {
14411443 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]
14431445 TypeTableEntry *entry_c_int[CIntTypeCount];
14441446 TypeTableEntry *entry_c_longdouble;
14451447 TypeTableEntry *entry_c_void;
......@@ -1639,12 +1641,6 @@ struct ErrorTableEntry {
16391641 ConstExprValue *cached_error_name_val;
16401642};
16411643
1642struct LabelTableEntry {
1643 AstNode *decl_node;
1644 IrBasicBlock *bb;
1645 bool used;
1646};
1647
16481644enum ScopeId {
16491645 ScopeIdDecls,
16501646 ScopeIdBlock,
......@@ -1688,7 +1684,12 @@ struct ScopeDecls {
16881684struct ScopeBlock {
16891685 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
16921693 bool safety_off;
16931694 AstNode *safety_set_node;
16941695 bool fast_math_off;
......@@ -1734,6 +1735,7 @@ struct ScopeCImport {
17341735struct ScopeLoop {
17351736 Scope base;
17361737
1738 Buf *name;
17371739 IrBasicBlock *break_block;
17381740 IrBasicBlock *continue_block;
17391741 IrInstruction *is_comptime;
......@@ -1885,8 +1887,6 @@ enum IrInstructionId {
18851887 IrInstructionIdCheckStatementIsVoid,
18861888 IrInstructionIdTypeName,
18871889 IrInstructionIdCanImplicitCast,
1888 IrInstructionIdSetGlobalSection,
1889 IrInstructionIdSetGlobalLinkage,
18901890 IrInstructionIdDeclRef,
18911891 IrInstructionIdPanic,
18921892 IrInstructionIdTagName,
......@@ -1900,6 +1900,7 @@ enum IrInstructionId {
19001900 IrInstructionIdOpaqueType,
19011901 IrInstructionIdSetAlignStack,
19021902 IrInstructionIdArgType,
1903 IrInstructionIdExport,
19031904};
19041905
19051906struct IrInstruction {
......@@ -2102,7 +2103,7 @@ struct IrInstructionCall {
21022103 IrInstruction **args;
21032104 bool is_comptime;
21042105 LLVMValueRef tmp_ptr;
2105 bool is_inline;
2106 FnInline fn_inline;
21062107};
21072108
21082109struct IrInstructionConst {
......@@ -2625,20 +2626,6 @@ struct IrInstructionCanImplicitCast {
26252626 IrInstruction *target_value;
26262627};
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
26422629struct IrInstructionDeclRef {
26432630 IrInstruction base;
26442631
......@@ -2727,6 +2714,14 @@ struct IrInstructionArgType {
27272714 IrInstruction *arg_index;
27282715};
27292716
2717struct IrInstructionExport {
2718 IrInstruction base;
2719
2720 IrInstruction *name;
2721 IrInstruction *linkage;
2722 IrInstruction *target;
2723};
2724
27302725static const size_t slice_ptr_index = 0;
27312726static 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) {
110110 assert(node->type == NodeTypeBlock);
111111 ScopeBlock *scope = allocate<ScopeBlock>(1);
112112 init_scope(&scope->base, ScopeIdBlock, node, parent);
113 scope->label_table.init(1);
113 scope->name = node->data.block.name;
114114 return scope;
115115}
116116
......@@ -144,9 +144,15 @@ ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent) {
144144}
145145
146146ScopeLoop *create_loop_scope(AstNode *node, Scope *parent) {
147 assert(node->type == NodeTypeWhileExpr || node->type == NodeTypeForExpr);
148147 ScopeLoop *scope = allocate<ScopeLoop>(1);
149148 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 }
150156 return scope;
151157}
152158
......@@ -429,7 +435,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
429435 ensure_complete_type(g, child_type);
430436
431437 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);
432 assert(child_type->type_ref);
438 assert(child_type->type_ref || child_type->zero_bits);
433439 assert(child_type->di_type);
434440 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
10621068 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
10631069
10641070 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;
10661072 fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified;
10671073 } else {
10681074 fn_type_id->cc = fn_proto->cc;
......@@ -1093,6 +1099,38 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_
10931099 return true;
10941100}
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
10961134static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) {
10971135 assert(proto_node->type == NodeTypeFnProto);
10981136 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
......@@ -1130,6 +1168,15 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
11301168 }
11311169
11321170 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
11341181 switch (type_entry->id) {
11351182 case TypeTableEntryIdInvalid:
......@@ -2227,7 +2274,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
22272274
22282275 tag_type = new_type_table_entry(TypeTableEntryIdEnum);
22292276 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));
22312278 tag_type->is_copyable = true;
22322279 tag_type->type_ref = tag_int_type->type_ref;
22332280 tag_type->zero_bits = tag_int_type->zero_bits;
......@@ -2244,12 +2291,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
22442291 TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
22452292 if (type_is_invalid(enum_type)) {
22462293 union_type->data.unionation.is_invalid = true;
2247 union_type->data.unionation.embedded_in_current = false;
22482294 return;
22492295 }
22502296 if (enum_type->id != TypeTableEntryIdEnum) {
22512297 union_type->data.unionation.is_invalid = true;
2252 union_type->data.unionation.embedded_in_current = false;
22532298 add_node_error(g, enum_type_node,
22542299 buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
22552300 return;
......@@ -2474,7 +2519,7 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) {
24742519 buf_append_buf(buf, tld->name);
24752520}
24762521
2477FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) {
2522FnTableEntry *create_fn_raw(FnInline inline_value) {
24782523 FnTableEntry *fn_entry = allocate<FnTableEntry>(1);
24792524
24802525 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
......@@ -2482,7 +2527,6 @@ FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) {
24822527 fn_entry->analyzed_executable.fn_entry = fn_entry;
24832528 fn_entry->ir_executable.fn_entry = fn_entry;
24842529 fn_entry->fn_inline = inline_value;
2485 fn_entry->linkage = linkage;
24862530
24872531 return fn_entry;
24882532}
......@@ -2492,9 +2536,7 @@ FnTableEntry *create_fn(AstNode *proto_node) {
24922536 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
24932537
24942538 FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto;
2495 GlobalLinkageId linkage = (fn_proto->visib_mod == VisibModExport || proto_node->data.fn_proto.is_extern) ?
2496 GlobalLinkageIdStrong : GlobalLinkageIdInternal;
2497 FnTableEntry *fn_entry = create_fn_raw(inline_value, linkage);
2539 FnTableEntry *fn_entry = create_fn_raw(inline_value);
24982540
24992541 fn_entry->proto_node = proto_node;
25002542 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) {
25502592 return g->test_fn_type;
25512593}
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
25532623static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
25542624 ImportTableEntry *import = tld_fn->base.import;
25552625 AstNode *source_node = tld_fn->base.source_node;
......@@ -2561,6 +2631,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
25612631 FnTableEntry *fn_table_entry = create_fn(source_node);
25622632 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
25642639 tld_fn->fn_entry = fn_table_entry;
25652640
25662641 if (fn_table_entry->body_node) {
......@@ -2574,7 +2649,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
25742649 add_node_error(g, param_node, buf_sprintf("missing parameter name"));
25752650 }
25762651 }
2577 } else if (fn_table_entry->linkage != GlobalLinkageIdInternal) {
2652 } else {
25782653 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);
25792654 }
25802655
......@@ -2582,6 +2657,15 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
25822657
25832658 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
25852669 if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) {
25862670 tld_fn->base.resolution = TldResolutionInvalid;
25872671 return;
......@@ -2596,15 +2680,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
25962680 {
25972681 if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
25982682 g->main_fn = fn_table_entry;
2599
2600 if (tld_fn->base.visib_mod != VisibModExport) {
2601 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
2602 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
2603 if (actual_return_type != err_void) {
2604 add_node_error(g, fn_proto->return_type,
2605 buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
2606 buf_ptr(&actual_return_type->name)));
2607 }
2683 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
2684 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
2685 if (actual_return_type != err_void) {
2686 add_node_error(g, fn_proto->return_type,
2687 buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
2688 buf_ptr(&actual_return_type->name)));
26082689 }
26092690 } else if ((import->package == g->panic_package || g->have_pub_panic) &&
26102691 buf_eql_str(&fn_table_entry->symbol_name, "panic"))
......@@ -2615,7 +2696,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
26152696 }
26162697 }
26172698 } 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
26202701 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) {
26422723}
26432724
26442725static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
2645 if (tld->visib_mod == VisibModExport) {
2646 g->resolve_queue.append(tld);
2726 bool is_export = false;
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;
26472733 }
2734 if (is_export) {
2735 g->resolve_queue.append(tld);
26482736
2649 if (tld->visib_mod == VisibModExport) {
2650 auto entry = g->exported_symbol_names.put_unique(tld->name, tld);
2737 auto entry = g->exported_symbol_names.put_unique(tld->name, tld->source_node);
26512738 if (entry) {
2652 Tld *other_tld = entry->value;
2739 AstNode *other_source_node = entry->value;
26532740 ErrorMsg *msg = add_node_error(g, tld->source_node,
26542741 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"));
26562743 }
26572744 }
26582745
......@@ -2731,7 +2818,6 @@ static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_s
27312818 g->resolve_queue.append(&tld_comptime->base);
27322819}
27332820
2734
27352821void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node,
27362822 Scope *parent_scope)
27372823{
......@@ -2836,8 +2922,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
28362922 case NodeTypeSwitchExpr:
28372923 case NodeTypeSwitchProng:
28382924 case NodeTypeSwitchRange:
2839 case NodeTypeLabel:
2840 case NodeTypeGoto:
28412925 case NodeTypeBreak:
28422926 case NodeTypeContinue:
28432927 case NodeTypeUnreachable:
......@@ -2987,8 +3071,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
29873071 AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration;
29883072
29893073 bool is_const = var_decl->is_const;
2990 bool is_export = (tld_var->base.visib_mod == VisibModExport);
29913074 bool is_extern = var_decl->is_extern;
3075 bool is_export = var_decl->is_export;
29923076
29933077 TypeTableEntry *explicit_type = nullptr;
29943078 if (var_decl->type) {
......@@ -2996,9 +3080,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
29963080 explicit_type = validate_var_type(g, var_decl->type, proposed_type);
29973081 }
29983082
2999 if (is_export && is_extern) {
3000 add_node_error(g, source_node, buf_sprintf("variable is both export and extern"));
3001 }
3083 assert(!is_export || !is_extern);
30023084
30033085 VarLinkage linkage;
30043086 if (is_export) {
......@@ -3009,7 +3091,6 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
30093091 linkage = VarLinkageInternal;
30103092 }
30113093
3012
30133094 IrInstruction *init_value = nullptr;
30143095
30153096 // 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) {
30583139 }
30593140 }
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
30613151 g->global_vars.append(tld_var);
30623152}
30633153
......@@ -3319,7 +3409,7 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {
33193409
33203410TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
33213411 assert(type_entry->id == TypeTableEntryIdUnion);
3322 assert(type_entry->data.unionation.complete);
3412 assert(type_entry->data.unionation.zero_bits_known);
33233413 for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
33243414 TypeUnionField *field = &type_entry->data.unionation.fields[i];
33253415 if (buf_eql_buf(field->enum_field->name, name)) {
......@@ -3331,7 +3421,7 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
33313421
33323422TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
33333423 assert(type_entry->id == TypeTableEntryIdUnion);
3334 assert(type_entry->data.unionation.complete);
3424 assert(type_entry->data.unionation.zero_bits_known);
33353425 assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX);
33363426 for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
33373427 TypeUnionField *field = &type_entry->data.unionation.fields[i];
......@@ -3726,8 +3816,10 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a
37263816 Buf *proto_name = proto_node->data.fn_proto.name;
37273817
37283818 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) {
37313823 if (buf_eql_str(proto_name, "main")) {
37323824 g->have_pub_main = true;
37333825 g->windows_subsystem_windows = false;
......@@ -3735,28 +3827,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a
37353827 } else if (buf_eql_str(proto_name, "panic")) {
37363828 g->have_pub_panic = true;
37373829 }
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;
37583830 }
3759
37603831 }
37613832 }
37623833
......@@ -3820,12 +3891,14 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_b
38203891 index = 6;
38213892 } else if (size_in_bits == 16) {
38223893 index = 7;
3823 } else if (size_in_bits == 32) {
3894 } else if (size_in_bits == 29) {
38243895 index = 8;
3825 } else if (size_in_bits == 64) {
3896 } else if (size_in_bits == 32) {
38263897 index = 9;
3827 } else if (size_in_bits == 128) {
3898 } else if (size_in_bits == 64) {
38283899 index = 10;
3900 } else if (size_in_bits == 128) {
3901 index = 11;
38293902 } else {
38303903 return nullptr;
38313904 }
......@@ -3888,7 +3961,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
38883961 return false;
38893962 case TypeTableEntryIdArray:
38903963 case TypeTableEntryIdStruct:
3891 case TypeTableEntryIdUnion:
38923964 return type_has_bits(type_entry);
38933965 case TypeTableEntryIdErrorUnion:
38943966 return type_has_bits(type_entry->data.error.child_type);
......@@ -3896,6 +3968,14 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
38963968 return type_has_bits(type_entry->data.maybe.child_type) &&
38973969 type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
38983970 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
38993979 }
39003980 zig_unreachable();
39013981}
......@@ -5438,3 +5518,4 @@ uint32_t type_ptr_hash(const TypeTableEntry *ptr) {
54385518bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {
54395519 return a == b;
54405520}
5521
src/analyze.hpp+4
......@@ -180,5 +180,9 @@ void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name);
180180
181181uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry);
182182TypeTableEntry *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
184188#endif
src/ast_render.cpp+48-25
......@@ -78,7 +78,6 @@ static const char *visib_mod_string(VisibMod mod) {
7878 switch (mod) {
7979 case VisibModPub: return "pub ";
8080 case VisibModPrivate: return "";
81 case VisibModExport: return "export ";
8281 }
8382 zig_unreachable();
8483}
......@@ -112,6 +111,10 @@ static const char *extern_string(bool is_extern) {
112111 return is_extern ? "extern " : "";
113112}
114113
114static const char *export_string(bool is_export) {
115 return is_export ? "export " : "";
116}
117
115118//static const char *calling_convention_string(CallingConvention cc) {
116119// switch (cc) {
117120// case CallingConventionUnspecified: return "";
......@@ -212,10 +215,6 @@ static const char *node_type_str(NodeType node_type) {
212215 return "SwitchProng";
213216 case NodeTypeSwitchRange:
214217 return "SwitchRange";
215 case NodeTypeLabel:
216 return "Label";
217 case NodeTypeGoto:
218 return "Goto";
219218 case NodeTypeCompTime:
220219 return "CompTime";
221220 case NodeTypeBreak:
......@@ -388,7 +387,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
388387 switch (node->type) {
389388 case NodeTypeSwitchProng:
390389 case NodeTypeSwitchRange:
391 case NodeTypeLabel:
392390 case NodeTypeStructValueField:
393391 zig_unreachable();
394392 case NodeTypeRoot:
......@@ -411,8 +409,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
411409 {
412410 const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);
413411 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);
414413 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);
416415 if (node->data.fn_proto.name != nullptr) {
417416 fprintf(ar->f, " ");
418417 print_symbol(ar, node->data.fn_proto.name);
......@@ -440,6 +439,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
440439 }
441440 }
442441 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
444453 AstNode *return_type_node = node->data.fn_proto.return_type;
445454 if (return_type_node != nullptr) {
......@@ -456,6 +465,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
456465 break;
457466 }
458467 case NodeTypeBlock:
468 if (node->data.block.name != nullptr) {
469 fprintf(ar->f, "%s: ", buf_ptr(node->data.block.name));
470 }
459471 if (node->data.block.statements.length == 0) {
460472 fprintf(ar->f, "{}");
461473 break;
......@@ -464,19 +476,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
464476 ar->indent += ar->indent_size;
465477 for (size_t i = 0; i < node->data.block.statements.length; i += 1) {
466478 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 }
474479 print_indent(ar);
475480 render_node_grouped(ar, statement);
476 if (!(i == node->data.block.statements.length - 1 &&
477 node->data.block.last_statement_is_result_expression)) {
478 fprintf(ar->f, ";");
479 }
481 fprintf(ar->f, ";");
480482 fprintf(ar->f, "\n");
481483 }
482484 ar->indent -= ar->indent_size;
......@@ -501,6 +503,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
501503 case NodeTypeBreak:
502504 {
503505 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 }
504509 if (node->data.break_expr.expr) {
505510 fprintf(ar->f, " ");
506511 render_node_grouped(ar, node->data.break_expr.expr);
......@@ -526,6 +531,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
526531 fprintf(ar->f, ": ");
527532 render_node_grouped(ar, node->data.variable_declaration.type);
528533 }
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 }
529544 if (node->data.variable_declaration.expr) {
530545 fprintf(ar->f, " = ");
531546 render_node_grouped(ar, node->data.variable_declaration.expr);
......@@ -584,12 +599,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
584599 PrefixOp op = node->data.prefix_op_expr.prefix_op;
585600 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);
588605 if (!grouped) fprintf(ar->f, ")");
589606 break;
590607 }
591608 case NodeTypeAddrOfExpr:
592609 {
610 if (!grouped) fprintf(ar->f, "(");
593611 fprintf(ar->f, "&");
594612 if (node->data.addr_of_expr.align_expr != nullptr) {
595613 fprintf(ar->f, "align(");
......@@ -617,6 +635,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
617635 }
618636
619637 render_node_ungrouped(ar, node->data.addr_of_expr.op_expr);
638 if (!grouped) fprintf(ar->f, ")");
620639 break;
621640 }
622641 case NodeTypeFnCallExpr:
......@@ -625,7 +644,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
625644 fprintf(ar->f, "@");
626645 }
627646 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);
629648 render_node_extra(ar, fn_ref_node, grouped);
630649 fprintf(ar->f, "(");
631650 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) {
800819 }
801820 case NodeTypeWhileExpr:
802821 {
822 if (node->data.while_expr.name != nullptr) {
823 fprintf(ar->f, "%s: ", buf_ptr(node->data.while_expr.name));
824 }
803825 const char *inline_str = node->data.while_expr.is_inline ? "inline " : "";
804826 fprintf(ar->f, "%swhile (", inline_str);
805827 render_node_grouped(ar, node->data.while_expr.condition);
......@@ -929,11 +951,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
929951 fprintf(ar->f, "}");
930952 break;
931953 }
932 case NodeTypeGoto:
933 {
934 fprintf(ar->f, "goto %s", buf_ptr(node->data.goto_expr.name));
935 break;
936 }
937954 case NodeTypeCompTime:
938955 {
939956 fprintf(ar->f, "comptime ");
......@@ -942,6 +959,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
942959 }
943960 case NodeTypeForExpr:
944961 {
962 if (node->data.for_expr.name != nullptr) {
963 fprintf(ar->f, "%s: ", buf_ptr(node->data.for_expr.name));
964 }
945965 const char *inline_str = node->data.for_expr.is_inline ? "inline " : "";
946966 fprintf(ar->f, "%sfor (", inline_str);
947967 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) {
967987 case NodeTypeContinue:
968988 {
969989 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 }
970993 break;
971994 }
972995 case NodeTypeUnreachable:
src/c_tokenizer.cpp+15
......@@ -121,6 +121,9 @@ static void begin_token(CTokenize *ctok, CTokId id) {
121121 case CTokIdRParen:
122122 case CTokIdEOF:
123123 case CTokIdDot:
124 case CTokIdAsterisk:
125 case CTokIdBang:
126 case CTokIdTilde:
124127 break;
125128 }
126129}
......@@ -228,10 +231,22 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
228231 begin_token(ctok, CTokIdRParen);
229232 end_token(ctok);
230233 break;
234 case '*':
235 begin_token(ctok, CTokIdAsterisk);
236 end_token(ctok);
237 break;
231238 case '-':
232239 begin_token(ctok, CTokIdMinus);
233240 end_token(ctok);
234241 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;
235250 default:
236251 return mark_error(ctok);
237252 }
src/c_tokenizer.hpp+3
......@@ -22,6 +22,9 @@ enum CTokId {
2222 CTokIdRParen,
2323 CTokIdEOF,
2424 CTokIdDot,
25 CTokIdAsterisk,
26 CTokIdBang,
27 CTokIdTilde,
2528};
2629
2730enum CNumLitSuffix {
src/codegen.cpp+139-60
......@@ -55,6 +55,10 @@ static PackageTableEntry *new_package(const char *root_src_dir, const char *root
5555 return entry;
5656}
5757
58PackageTableEntry *new_anonymous_package(void) {
59 return new_package("", "");
60}
61
5862CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
5963 Buf *zig_lib_dir)
6064{
......@@ -387,24 +391,51 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) {
387391 }
388392}
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
390408static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
391409 if (fn_table_entry->llvm_value)
392410 return fn_table_entry->llvm_value;
393411
394 bool external_linkage = (fn_table_entry->linkage != GlobalLinkageIdInternal);
395 Buf *symbol_name = get_mangled_name(g, &fn_table_entry->symbol_name, external_linkage);
412 Buf *unmangled_name = &fn_table_entry->symbol_name;
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;
397428 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall && external_linkage &&
398429 g->zig_target.arch.arch == ZigLLVM_x86)
399430 {
400 // prevent name mangling
431 // prevent llvm name mangling
401432 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));
402433 }
403434
404435
405436 TypeTableEntry *fn_type = fn_table_entry->type_entry;
406437 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) {
408439 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
409440 if (existing_llvm_fn) {
410441 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) {
414445 }
415446 } else {
416447 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 }
417454 }
418455 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) {
441478 }
442479 }
443480
444 switch (fn_table_entry->linkage) {
445 case GlobalLinkageIdInternal:
446 LLVMSetLinkage(fn_table_entry->llvm_value, LLVMInternalLinkage);
447 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;
481 LLVMSetLinkage(fn_table_entry->llvm_value, to_llvm_linkage(linkage));
482
483 if (linkage == GlobalLinkageIdInternal) {
484 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);
458485 }
459486
460487 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) {
561588 bool is_definition = fn_table_entry->body_node != nullptr;
562589 unsigned flags = 0;
563590 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);
565593 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
566594 get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "",
567595 import->di_file, line_number,
......@@ -839,7 +867,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
839867 assert(g->panic_fn != nullptr);
840868 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
841869 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, "");
843871 LLVMBuildUnreachable(g->builder);
844872}
845873
......@@ -988,7 +1016,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
9881016static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
9891017 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
9901018 ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified),
991 false, "");
1019 ZigLLVM_FnInlineAuto, "");
9921020 LLVMBuildUnreachable(g->builder);
9931021}
9941022
......@@ -1210,11 +1238,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry
12101238 return nullptr;
12111239 }
12121240
1241 bool big_endian = g->is_big_endian;
1242
12131243 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
12141244
12151245 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
12161246 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;
12181248 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
12191249
12201250 LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);
......@@ -2170,12 +2200,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
21702200 if (unaligned_bit_count == 0)
21712201 return get_handle_value(g, ptr, child_type, ptr_type);
21722202
2203 bool big_endian = g->is_big_endian;
2204
21732205 assert(!handle_is_ptr(child_type));
21742206 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
21752207
21762208 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
21772209 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
21802212 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
21812213 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
23162348 }
23172349 }
23182350
2319 bool want_always_inline = (instruction->fn_entry != nullptr &&
2320 instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_inline;
2351 ZigLLVM_FnInline fn_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
23222364 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
23232365 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
23262368 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
23272369 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
26842726}
26852727
26862728static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRef *instruction) {
2729 if (!type_has_bits(instruction->base.value.type)) {
2730 return nullptr;
2731 }
26872732 LLVMValueRef value = ir_llvm_value(g, instruction->value);
26882733 if (handle_is_ptr(instruction->value->value.type)) {
26892734 return value;
......@@ -2975,6 +3020,15 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
29753020 add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
29763021 }
29773022 }
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
29793033 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
29803034 LLVMValueRef indices[] = {
......@@ -3473,8 +3527,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
34733527 case IrInstructionIdCheckStatementIsVoid:
34743528 case IrInstructionIdTypeName:
34753529 case IrInstructionIdCanImplicitCast:
3476 case IrInstructionIdSetGlobalSection:
3477 case IrInstructionIdSetGlobalLinkage:
34783530 case IrInstructionIdDeclRef:
34793531 case IrInstructionIdSwitchVar:
34803532 case IrInstructionIdOffsetOf:
......@@ -3485,6 +3537,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
34853537 case IrInstructionIdSetAlignStack:
34863538 case IrInstructionIdArgType:
34873539 case IrInstructionIdTagType:
3540 case IrInstructionIdExport:
34883541 zig_unreachable();
34893542 case IrInstructionIdReturn:
34903543 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
37473800 case TypeTableEntryIdStruct:
37483801 {
37493802 assert(type_entry->data.structure.layout == ContainerLayoutPacked);
3803 bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
37503804
37513805 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
3806 size_t used_bits = 0;
37523807 for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
37533808 TypeStructField *field = &type_entry->data.structure.fields[i];
37543809 if (field->gen_index == SIZE_MAX) {
37553810 continue;
37563811 }
37573812 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);
3759 val = LLVMConstShl(val, shift_amt);
3760 val = LLVMConstOr(val, child_val);
3813 if (is_big_endian) {
3814 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, field->packed_bits_size, false);
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 }
37613823 }
37623824 return val;
37633825 }
......@@ -3882,9 +3944,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
38823944 fields[type_struct_field->gen_index] = val;
38833945 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
38843946 } else {
3947 bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
38853948 LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref,
38863949 (unsigned)type_struct_field->gen_index);
38873950 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
3951 size_t used_bits = 0;
38883952 for (size_t i = src_field_index; i < src_field_index_end; i += 1) {
38893953 TypeStructField *it_field = &type_entry->data.structure.fields[i];
38903954 if (it_field->gen_index == SIZE_MAX) {
......@@ -3892,10 +3956,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
38923956 }
38933957 LLVMValueRef child_val = pack_const_int(g, big_int_type_ref,
38943958 &const_val->data.x_struct.fields[i]);
3895 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref,
3896 it_field->packed_bits_size, false);
3897 val = LLVMConstShl(val, shift_amt);
3898 val = LLVMConstOr(val, child_val);
3959 if (is_big_endian) {
3960 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref,
3961 it_field->packed_bits_size, false);
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 }
38993970 }
39003971 fields[type_struct_field->gen_index] = val;
39013972 }
......@@ -3946,8 +4017,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
39464017 case TypeTableEntryIdUnion:
39474018 {
39484019 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
39524021 if (type_entry->data.unionation.gen_field_count == 0) {
39534022 if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
......@@ -3960,7 +4029,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
39604029
39614030 LLVMValueRef union_value_ref;
39624031 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)) {
39644034 if (type_entry->data.unionation.gen_tag_index == SIZE_MAX)
39654035 return LLVMGetUndef(type_entry->type_ref);
39664036
......@@ -4635,6 +4705,7 @@ static const uint8_t int_sizes_in_bits[] = {
46354705 7,
46364706 8,
46374707 16,
4708 29,
46384709 32,
46394710 64,
46404711 128,
......@@ -4955,8 +5026,6 @@ static void define_builtin_fns(CodeGen *g) {
49555026 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
49565027 create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
49575028 create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2);
4958 create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
4959 create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
49605029 create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1);
49615030 create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2);
49625031 create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2);
......@@ -4972,6 +5041,7 @@ static void define_builtin_fns(CodeGen *g) {
49725041 create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
49735042 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
49745043 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
5044 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
49755045 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
49765046 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
49775047 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
......@@ -4980,6 +5050,7 @@ static void define_builtin_fns(CodeGen *g) {
49805050 create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);
49815051 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
49825052 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
5053 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
49835054}
49845055
49855056static const char *bool_to_str(bool b) {
......@@ -5298,18 +5369,19 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {
52985369
52995370 ZigList<ErrorMsg *> errors = {0};
53005371 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) {
53075374 for (size_t i = 0; i < errors.length; i += 1) {
53085375 ErrorMsg *err_msg = errors.at(i);
53095376 print_err_msg(err_msg, g->err_color);
53105377 }
53115378 exit(1);
53125379 }
5380
5381 if (err) {
5382 fprintf(stderr, "unable to parse C file: %s\n", err_str(err));
5383 exit(1);
5384 }
53135385}
53145386
53155387static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) {
......@@ -5417,6 +5489,27 @@ static void gen_root_source(CodeGen *g) {
54175489 assert(g->root_out_name);
54185490 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
54205513 if (!g->is_test_build && g->zig_target.os != ZigLLVM_UnknownOS &&
54215514 !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup &&
54225515 ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe))
......@@ -5426,20 +5519,6 @@ static void gen_root_source(CodeGen *g) {
54265519 if (g->zig_target.os == ZigLLVM_Win32 && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib) {
54275520 g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig");
54285521 }
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
54445523 if (!g->error_during_imports) {
54455524 semantic_analyze(g);
......@@ -5666,7 +5745,7 @@ static void gen_h_file(CodeGen *g) {
56665745 for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) {
56675746 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)
56705749 continue;
56715750
56725751 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 *) {
207207 return IrInstructionIdDeclVar;
208208}
209209
210static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) {
211 return IrInstructionIdExport;
212}
213
210214static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) {
211215 return IrInstructionIdLoadPtr;
212216}
......@@ -523,14 +527,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast
523527 return IrInstructionIdCanImplicitCast;
524528}
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
534530static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) {
535531 return IrInstructionIdDeclRef;
536532}
......@@ -928,13 +924,13 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
928924
929925static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
930926 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)
932928{
933929 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
934930 call_instruction->fn_entry = fn_entry;
935931 call_instruction->fn_ref = fn_ref;
936932 call_instruction->is_comptime = is_comptime;
937 call_instruction->is_inline = is_inline;
933 call_instruction->fn_inline = fn_inline;
938934 call_instruction->args = args;
939935 call_instruction->arg_count = arg_count;
940936
......@@ -948,10 +944,10 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
948944
949945static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
950946 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)
952948{
953949 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);
955951 ir_link_new_instruction(new_instruction, old_instruction);
956952 return new_instruction;
957953}
......@@ -1025,7 +1021,7 @@ static IrInstruction *ir_build_ptr_type_of(IrBuilder *irb, Scope *scope, AstNode
10251021 ptr_type_of_instruction->bit_offset_start = bit_offset_start;
10261022 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);
10291025 ir_ref_instruction(child_type, irb->current_basic_block);
10301026
10311027 return &ptr_type_of_instruction->base;
......@@ -1191,6 +1187,8 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s
11911187 if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
11921188 ir_ref_instruction(init_value, irb->current_basic_block);
11931189
1190 var->decl_instruction = &decl_var_instruction->base;
1191
11941192 return &decl_var_instruction->base;
11951193}
11961194
......@@ -1203,6 +1201,24 @@ static IrInstruction *ir_build_var_decl_from(IrBuilder *irb, IrInstruction *old_
12031201 return new_instruction;
12041202}
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
12061222static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) {
12071223 IrInstructionLoadPtr *instruction = ir_build_instruction<IrInstructionLoadPtr>(irb, scope, source_node);
12081224 instruction->ptr = ptr;
......@@ -2157,32 +2173,6 @@ static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, A
21572173 return &instruction->base;
21582174}
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
21862176static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node,
21872177 Tld *tld, LVal lval)
21882178{
......@@ -2394,6 +2384,21 @@ static IrInstruction *ir_instruction_declvar_get_dep(IrInstructionDeclVar *instr
23942384 return nullptr;
23952385}
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
23972402static IrInstruction *ir_instruction_loadptr_get_dep(IrInstructionLoadPtr *instruction, size_t index) {
23982403 switch (index) {
23992404 case 0: return instruction->ptr;
......@@ -2977,20 +2982,6 @@ static IrInstruction *ir_instruction_canimplicitcast_get_dep(IrInstructionCanImp
29772982 }
29782983}
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
29942985static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) {
29952986 return nullptr;
29962987}
......@@ -3104,6 +3095,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
31043095 return ir_instruction_binop_get_dep((IrInstructionBinOp *) instruction, index);
31053096 case IrInstructionIdDeclVar:
31063097 return ir_instruction_declvar_get_dep((IrInstructionDeclVar *) instruction, index);
3098 case IrInstructionIdExport:
3099 return ir_instruction_export_get_dep((IrInstructionExport *) instruction, index);
31073100 case IrInstructionIdLoadPtr:
31083101 return ir_instruction_loadptr_get_dep((IrInstructionLoadPtr *) instruction, index);
31093102 case IrInstructionIdStorePtr:
......@@ -3262,10 +3255,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
32623255 return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index);
32633256 case IrInstructionIdCanImplicitCast:
32643257 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);
32693258 case IrInstructionIdDeclRef:
32703259 return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index);
32713260 case IrInstructionIdPanic:
......@@ -3522,33 +3511,14 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s
35223511 return var;
35233512}
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
35483514static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
35493515 assert(block_node->type == NodeTypeBlock);
35503516
3517 ZigList<IrInstruction *> incoming_values = {0};
3518 ZigList<IrBasicBlock *> incoming_blocks = {0};
3519
35513520 ScopeBlock *scope_block = create_block_scope(block_node, parent_scope);
3521
35523522 Scope *outer_block_scope = &scope_block->base;
35533523 Scope *child_scope = outer_block_scope;
35543524
......@@ -3562,44 +3532,18 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
35623532 return ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
35633533 }
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
35653542 bool is_continuation_unreachable = false;
35663543 IrInstruction *noreturn_return_value = nullptr;
3567 IrInstruction *return_value = nullptr;
35683544 for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
35693545 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
36033547 IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope);
36043548 is_continuation_unreachable = instr_is_unreachable(statement_value);
36053549 if (is_continuation_unreachable) {
......@@ -3614,39 +3558,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
36143558 // variable declarations start a new scope
36153559 IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value;
36163560 child_scope = decl_var_instruction->var->child_scope;
3617 } else {
3618 // label, defer, variable declaration will never be the result expression
3619 if (block_node->data.block.last_statement_is_result_expression &&
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 }
3561 } else if (statement_value != irb->codegen->invalid_instruction) {
3562 // this statement's value must be void
3563 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value));
36293564 }
36303565 }
36313566
36323567 if (is_continuation_unreachable) {
36333568 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)));
36353575 }
3636 // control flow falls out of block
36373576
3638 if (block_node->data.block.last_statement_is_result_expression) {
3639 // return value was determined by the last statement
3640 assert(return_value != nullptr);
3577 if (block_node->data.block.name != nullptr) {
3578 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
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);
36413582 } else {
3642 // return value is implicitly void
3643 assert(return_value == nullptr);
3644 return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
3583 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3584 return ir_mark_gen(ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)));
36453585 }
3646
3647 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3648
3649 return return_value;
36503586}
36513587
36523588static 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
45264462
45274463 return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value);
45284464 }
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 }
45624465 case BuiltinFnIdPanic:
45634466 {
45644467 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
46724575 return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);
46734576 }
46744577 case BuiltinFnIdInlineCall:
4578 case BuiltinFnIdNoInlineCall:
46754579 {
46764580 if (node->data.fn_call_expr.params.length == 0) {
46774581 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
46924596 if (args[i] == irb->codegen->invalid_instruction)
46934597 return args[i];
46944598 }
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);
46974602 }
46984603 case BuiltinFnIdTypeId:
46994604 {
......@@ -4780,6 +4685,25 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
47804685
47814686 return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
47824687 }
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 }
47834707 }
47844708 zig_unreachable();
47854709}
......@@ -4804,7 +4728,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
48044728 return args[i];
48054729 }
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);
48084732}
48094733
48104734static 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
48954819 AstNode *expr_node = node->data.addr_of_expr.op_expr;
48964820 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) {
48994823 return ir_gen_node_extra(irb, expr_node, scope, make_lval_addr(is_const, is_volatile));
49004824 }
49014825
4902 IrInstruction *align_value = ir_gen_node(irb, align_expr, scope);
4903 if (align_value == irb->codegen->invalid_instruction)
4904 return align_value;
4826 IrInstruction *align_value;
4827 if (align_expr != nullptr) {
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
49064835 IrInstruction *child_type = ir_gen_node(irb, expr_node, scope);
49074836 if (child_type == irb->codegen->invalid_instruction)
......@@ -5078,7 +5007,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
50785007 bool is_const = variable_declaration->is_const;
50795008 bool is_extern = variable_declaration->is_extern;
50805009 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);
50825011 VariableTableEntry *var = ir_create_var(irb, node, scope, variable_declaration->symbol,
50835012 is_const, is_const, is_shadowable, is_comptime);
50845013 // 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
50975026 return align_value;
50985027 }
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
51005034 IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope);
51015035 if (init_value == irb->codegen->invalid_instruction)
51025036 return init_value;
51035037
5104 IrInstruction *result = ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value);
5105 var->decl_instruction = result;
5106 return result;
5038 return ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value);
51075039}
51085040
51095041static 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 *
60155947 return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
60165948}
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
60345950static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) {
60355951 assert(node->type == NodeTypeCompTime);
60365952
......@@ -6038,6 +5954,31 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo
60385954 return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval);
60395955}
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
60415982static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) {
60425983 assert(node->type == NodeTypeBreak);
60435984
......@@ -6045,19 +5986,38 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
60455986 // * function definition scope or global scope => error, break outside loop
60465987 // * defer expression scope => error, cannot break out of defer expression
60475988 // * loop scope => OK
5989 // * (if it's a labeled break) labeled block => OK
60485990
60495991 Scope *search_scope = break_scope;
60505992 ScopeLoop *loop_scope;
60515993 for (;;) {
60525994 if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
6053 add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop"));
6054 return irb->codegen->invalid_instruction;
5995 if (node->data.break_expr.name != nullptr) {
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 }
60556002 } else if (search_scope->id == ScopeIdDeferExpr) {
60566003 add_node_error(irb->codegen, node, buf_sprintf("cannot break out of defer expression"));
60576004 return irb->codegen->invalid_instruction;
60586005 } else if (search_scope->id == ScopeIdLoop) {
6059 loop_scope = (ScopeLoop *)search_scope;
6060 break;
6006 ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
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 }
60616021 }
60626022 search_scope = search_scope->parent;
60636023 }
......@@ -6098,14 +6058,24 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
60986058 ScopeLoop *loop_scope;
60996059 for (;;) {
61006060 if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
6101 add_node_error(irb->codegen, node, buf_sprintf("continue expression outside loop"));
6102 return irb->codegen->invalid_instruction;
6061 if (node->data.continue_expr.name != nullptr) {
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 }
61036068 } else if (search_scope->id == ScopeIdDeferExpr) {
61046069 add_node_error(irb->codegen, node, buf_sprintf("cannot continue out of defer expression"));
61056070 return irb->codegen->invalid_instruction;
61066071 } else if (search_scope->id == ScopeIdLoop) {
6107 loop_scope = (ScopeLoop *)search_scope;
6108 break;
6072 ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
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 }
61096079 }
61106080 search_scope = search_scope->parent;
61116081 }
......@@ -6347,7 +6317,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
63476317 case NodeTypeSwitchProng:
63486318 case NodeTypeSwitchRange:
63496319 case NodeTypeStructField:
6350 case NodeTypeLabel:
6320 case NodeTypeFnDef:
6321 case NodeTypeFnDecl:
6322 case NodeTypeErrorValueDecl:
6323 case NodeTypeTestDecl:
63516324 zig_unreachable();
63526325 case NodeTypeBlock:
63536326 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
64076380 return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval);
64086381 case NodeTypeSwitchExpr:
64096382 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);
64126383 case NodeTypeCompTime:
64136384 return ir_gen_comptime(irb, scope, node, lval);
64146385 case NodeTypeErrorType:
......@@ -6429,14 +6400,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
64296400 return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
64306401 case NodeTypeFnProto:
64316402 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");
64406403 }
64416404 zig_unreachable();
64426405}
......@@ -6451,70 +6414,6 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) {
64516414 return ir_gen_node_extra(irb, node, scope, LVAL_NONE);
64526415}
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
65186417static void invalidate_exec(IrExecutable *exec) {
65196418 if (exec->invalid)
65206419 return;
......@@ -6551,11 +6450,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
65516450 ir_mark_gen(ir_build_return(irb, scope, result->source_node, result));
65526451 }
65536452
6554 if (!ir_goto_pass2(irb)) {
6555 invalidate_exec(ir_executable);
6556 return false;
6557 }
6558
65596453 return true;
65606454}
65616455
......@@ -7468,6 +7362,41 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
74687362 }
74697363 }
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
74717400 // implicit undefined literal to anything
74727401 if (actual_type->id == TypeTableEntryIdUndefLit) {
74737402 return ImplicitCastMatchResultYes;
......@@ -7497,33 +7426,53 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
74977426 IrInstruction *cur_inst = instructions[i];
74987427 TypeTableEntry *cur_type = cur_inst->value.type;
74997428 TypeTableEntry *prev_type = prev_inst->value.type;
7429
75007430 if (type_is_invalid(cur_type)) {
75017431 return cur_type;
7502 } else if (prev_type->id == TypeTableEntryIdUnreachable) {
7432 }
7433
7434 if (prev_type->id == TypeTableEntryIdUnreachable) {
75037435 prev_inst = cur_inst;
7504 } else if (cur_type->id == TypeTableEntryIdUnreachable) {
75057436 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) {
75077444 prev_inst = cur_inst;
75087445 continue;
7509 } else if (prev_type->id == TypeTableEntryIdNullLit) {
7446 }
7447
7448 if (prev_type->id == TypeTableEntryIdNullLit) {
75107449 prev_inst = cur_inst;
75117450 continue;
7512 } else if (cur_type->id == TypeTableEntryIdPureError) {
7451 }
7452
7453 if (cur_type->id == TypeTableEntryIdPureError) {
75137454 if (prev_type->id == TypeTableEntryIdArray) {
75147455 convert_to_const_slice = true;
75157456 }
75167457 any_are_pure_error = true;
75177458 continue;
7518 } else if (cur_type->id == TypeTableEntryIdNullLit) {
7459 }
7460
7461 if (cur_type->id == TypeTableEntryIdNullLit) {
75197462 any_are_null = true;
75207463 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)) {
75227467 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)) {
75247471 prev_inst = cur_inst;
75257472 continue;
7526 } else if (prev_type->id == TypeTableEntryIdInt &&
7473 }
7474
7475 if (prev_type->id == TypeTableEntryIdInt &&
75277476 cur_type->id == TypeTableEntryIdInt &&
75287477 prev_type->data.integral.is_signed == cur_type->data.integral.is_signed)
75297478 {
......@@ -7531,36 +7480,51 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
75317480 prev_inst = cur_inst;
75327481 }
75337482 continue;
7534 } else if (prev_type->id == TypeTableEntryIdFloat &&
7535 cur_type->id == TypeTableEntryIdFloat)
7536 {
7483 }
7484
7485 if (prev_type->id == TypeTableEntryIdFloat && cur_type->id == TypeTableEntryIdFloat) {
75377486 if (cur_type->data.floating.bit_count > prev_type->data.floating.bit_count) {
75387487 prev_inst = cur_inst;
75397488 }
7540 } else if (prev_type->id == TypeTableEntryIdErrorUnion &&
7489 continue;
7490 }
7491
7492 if (prev_type->id == TypeTableEntryIdErrorUnion &&
75417493 types_match_const_cast_only(prev_type->data.error.child_type, cur_type))
75427494 {
75437495 continue;
7544 } else if (cur_type->id == TypeTableEntryIdErrorUnion &&
7496 }
7497
7498 if (cur_type->id == TypeTableEntryIdErrorUnion &&
75457499 types_match_const_cast_only(cur_type->data.error.child_type, prev_type))
75467500 {
75477501 prev_inst = cur_inst;
75487502 continue;
7549 } else if (prev_type->id == TypeTableEntryIdMaybe &&
7503 }
7504
7505 if (prev_type->id == TypeTableEntryIdMaybe &&
75507506 types_match_const_cast_only(prev_type->data.maybe.child_type, cur_type))
75517507 {
75527508 continue;
7553 } else if (cur_type->id == TypeTableEntryIdMaybe &&
7509 }
7510
7511 if (cur_type->id == TypeTableEntryIdMaybe &&
75547512 types_match_const_cast_only(cur_type->data.maybe.child_type, prev_type))
75557513 {
75567514 prev_inst = cur_inst;
75577515 continue;
7558 } else if (cur_type->id == TypeTableEntryIdUndefLit) {
7516 }
7517
7518 if (cur_type->id == TypeTableEntryIdUndefLit) {
75597519 continue;
7560 } else if (prev_type->id == TypeTableEntryIdUndefLit) {
7520 }
7521
7522 if (prev_type->id == TypeTableEntryIdUndefLit) {
75617523 prev_inst = cur_inst;
75627524 continue;
7563 } else if (prev_type->id == TypeTableEntryIdNumLitInt ||
7525 }
7526
7527 if (prev_type->id == TypeTableEntryIdNumLitInt ||
75647528 prev_type->id == TypeTableEntryIdNumLitFloat)
75657529 {
75667530 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
75697533 } else {
75707534 return ira->codegen->builtin_types.entry_invalid;
75717535 }
7572 } else if (cur_type->id == TypeTableEntryIdNumLitInt ||
7536 }
7537
7538 if (cur_type->id == TypeTableEntryIdNumLitInt ||
75737539 cur_type->id == TypeTableEntryIdNumLitFloat)
75747540 {
75757541 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
75777543 } else {
75787544 return ira->codegen->builtin_types.entry_invalid;
75797545 }
7580 } else if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
7546 }
7547
7548 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
75817549 cur_type->data.array.len != prev_type->data.array.len &&
75827550 types_match_const_cast_only(cur_type->data.array.child_type, prev_type->data.array.child_type))
75837551 {
75847552 convert_to_const_slice = true;
75857553 prev_inst = cur_inst;
75867554 continue;
7587 } else if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
7555 }
7556
7557 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
75887558 cur_type->data.array.len != prev_type->data.array.len &&
75897559 types_match_const_cast_only(prev_type->data.array.child_type, cur_type->data.array.child_type))
75907560 {
75917561 convert_to_const_slice = true;
75927562 continue;
7593 } else if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) &&
7563 }
7564
7565 if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) &&
75947566 (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
75957567 cur_type->data.array.len == 0) &&
75967568 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
75987570 {
75997571 convert_to_const_slice = false;
76007572 continue;
7601 } else if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) &&
7573 }
7574
7575 if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) &&
76027576 (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
76037577 prev_type->data.array.len == 0) &&
76047578 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
76077581 prev_inst = cur_inst;
76087582 convert_to_const_slice = false;
76097583 continue;
7610 } else {
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)));
7584 }
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 }
76207607 }
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;
76217618 }
76227619 if (convert_to_const_slice) {
76237620 assert(prev_inst->value.type->id == TypeTableEntryIdArray);
......@@ -7664,8 +7661,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
76647661static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *type_entry) {
76657662 if (type_has_bits(type_entry) && handle_is_ptr(type_entry)) {
76667663 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
7667 assert(fn_entry);
7668 fn_entry->alloca_list.append(instruction);
7664 if (fn_entry != nullptr) {
7665 fn_entry->alloca_list.append(instruction);
7666 }
76697667 }
76707668}
76717669
......@@ -7767,9 +7765,7 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
77677765 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op);
77687766 result->value.type = wanted_type;
77697767 if (need_alloca) {
7770 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
7771 if (fn_entry)
7772 fn_entry->alloca_list.append(result);
7768 ir_add_alloca(ira, result, wanted_type);
77737769 }
77747770 return result;
77757771 }
......@@ -8203,6 +8199,7 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_
82038199 assert(fn_entry);
82048200 fn_entry->alloca_list.append(new_instruction);
82058201 }
8202 ir_add_alloca(ira, new_instruction, child_type);
82068203 return new_instruction;
82078204 }
82088205}
......@@ -8246,13 +8243,15 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
82468243
82478244 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type,
82488245 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);
82518246 IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
82528247 source_instruction->source_node, value, is_const, is_volatile);
82538248 new_instruction->value.type = ptr_type;
82548249 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 }
82568255 return new_instruction;
82578256}
82588257
......@@ -8370,6 +8369,63 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc
83708369 return result;
83718370}
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
83738429static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr,
83748430 IrInstruction *target, TypeTableEntry *wanted_type)
83758431{
......@@ -8436,14 +8492,16 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
84368492 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
84378493 if (!val)
84388494 return ira->codegen->invalid_instruction;
8439 BigInt enum_member_count;
8440 bigint_init_unsigned(&enum_member_count, wanted_type->data.enumeration.src_field_count);
8441 if (bigint_cmp(&val->data.x_bigint, &enum_member_count) != CmpLT) {
8495
8496 TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint);
8497 if (field == nullptr) {
84428498 Buf *val_buf = buf_alloc();
84438499 bigint_append_buf(val_buf, &val->data.x_bigint, 10);
8444 ir_add_error(ira, source_instr,
8445 buf_sprintf("integer value %s too big for enum '%s' which has %" PRIu32 " fields",
8446 buf_ptr(val_buf), buf_ptr(&wanted_type->name), wanted_type->data.enumeration.src_field_count));
8500 ErrorMsg *msg = ir_add_error(ira, source_instr,
8501 buf_sprintf("enum '%s' has no tag matching integer value %s",
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)));
84478505 return ira->codegen->invalid_instruction;
84488506 }
84498507
......@@ -8827,7 +8885,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
88278885 if (actual_type->id == TypeTableEntryIdNumLitFloat ||
88288886 actual_type->id == TypeTableEntryIdNumLitInt)
88298887 {
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 &&
88318899 wanted_type->data.pointer.is_const)
88328900 {
88338901 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
89078975 }
89088976 }
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
89109010 // explicit cast from undefined to anything
89119011 if (actual_type->id == TypeTableEntryIdUndefLit) {
89129012 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
93349434 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);
93359435 if (type_is_invalid(resolved_type))
93369436 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
93389442 AstNode *source_node = bin_op_instruction->base.source_node;
93399443 switch (resolved_type->id) {
......@@ -9398,7 +9502,8 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
93989502
93999503 ConstExprValue *op1_val = &casted_op1->value;
94009504 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))) {
94029507 bool answer;
94039508 if (resolved_type->id == TypeTableEntryIdNumLitFloat || resolved_type->id == TypeTableEntryIdFloat) {
94049509 Cmp cmp_result = float_cmp(op1_val, op2_val);
......@@ -9407,7 +9512,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
94079512 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
94089513 answer = resolve_cmp_op_id(op_id, cmp_result);
94099514 } 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);
94119516 if (op_id == IrBinOpCmpEq) {
94129517 answer = are_equal;
94139518 } else if (op_id == IrBinOpCmpNotEq) {
......@@ -10265,6 +10370,170 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1026510370 return ira->codegen->builtin_types.entry_void;
1026610371}
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
1026810537static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
1026910538 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
1027010539{
......@@ -10442,7 +10711,7 @@ no_mem_slot:
1044210711
1044310712static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
1044410713 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)
1044610715{
1044710716 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
1044810717 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
1070110970
1070210971 if (type_requires_comptime(return_type)) {
1070310972 // 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);
1070510974 }
1070610975 }
1070710976
......@@ -10725,7 +10994,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1072510994
1072610995 size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
1072710996 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
1073010999 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
1073111000 ir_add_alloca(ira, new_call_instruction, return_type);
......@@ -10784,7 +11053,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1078411053 return ira->codegen->builtin_types.entry_invalid;
1078511054
1078611055 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
1078911058 ir_add_alloca(ira, new_call_instruction, return_type);
1079011059 return ir_finish_anal(ira, return_type);
......@@ -10823,13 +11092,13 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
1082311092 } else if (fn_ref->value.type->id == TypeTableEntryIdFn) {
1082411093 FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref);
1082511094 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);
1082711096 } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) {
1082811097 assert(fn_ref->value.special == ConstValSpecialStatic);
1082911098 FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn;
1083011099 IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg;
1083111100 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);
1083311102 } else {
1083411103 ir_add_error_node(ira, fn_ref->source_node,
1083511104 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
1083911108
1084011109 if (fn_ref->value.type->id == TypeTableEntryIdFn) {
1084111110 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);
1084311112 } else {
1084411113 ir_add_error_node(ira, fn_ref->source_node,
1084511114 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,
1218312452 return ira->codegen->builtin_types.entry_type;
1218412453}
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
1228212455static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,
1228312456 IrInstructionSetDebugSafety *set_debug_safety_instruction)
1228412457{
......@@ -12999,6 +13172,16 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1299913172 return tag_type;
1300013173 }
1300113174 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
1300213185 if (pointee_val) {
1300313186 ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
1300413187 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
1386514048 ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
1386614049 child_import->decls_scope = create_decls_scope(node, nullptr, nullptr, child_import);
1386714050 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
1386914055 ZigList<ErrorMsg *> errors = {0};
1387014056
......@@ -15735,8 +15921,12 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_of(IrAnalyze *ira, IrInst
1573515921 return ira->codegen->builtin_types.entry_invalid;
1573615922
1573715923 uint32_t align_bytes;
15738 if (!ir_resolve_align(ira, instruction->align_value->other, &align_bytes))
15739 return ira->codegen->builtin_types.entry_invalid;
15924 if (instruction->align_value != nullptr) {
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
1574115931 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1574215932 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
1593216122 return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction);
1593316123 case IrInstructionIdPtrTypeChild:
1593416124 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);
1593916125 case IrInstructionIdSetDebugSafety:
1594016126 return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction);
1594116127 case IrInstructionIdSetFloatMode:
......@@ -16078,6 +16264,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1607816264 return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction);
1607916265 case IrInstructionIdTagType:
1608016266 return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);
16267 case IrInstructionIdExport:
16268 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);
1608116269 }
1608216270 zig_unreachable();
1608316271}
......@@ -16185,12 +16373,11 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1618516373 case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free
1618616374 case IrInstructionIdCheckSwitchProngs:
1618716375 case IrInstructionIdCheckStatementIsVoid:
16188 case IrInstructionIdSetGlobalSection:
16189 case IrInstructionIdSetGlobalLinkage:
1619016376 case IrInstructionIdPanic:
1619116377 case IrInstructionIdSetEvalBranchQuota:
1619216378 case IrInstructionIdPtrTypeOf:
1619316379 case IrInstructionIdSetAlignStack:
16380 case IrInstructionIdExport:
1619416381 return true;
1619516382 case IrInstructionIdPhi:
1619616383 case IrInstructionIdUnOp:
src/ir_print.cpp+27-21
......@@ -886,8 +886,12 @@ static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCas
886886}
887887
888888static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instruction) {
889 fprintf(irp->f, "&align ");
890 ir_print_other_instruction(irp, instruction->align_value);
889 fprintf(irp->f, "&");
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 }
891895 const char *const_str = instruction->is_const ? "const " : "";
892896 const char *volatile_str = instruction->is_volatile ? "volatile " : "";
893897 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
895899 ir_print_other_instruction(irp, instruction->child_type);
896900}
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
911902static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) {
912903 const char *ptr_str = instruction->lval.is_ptr ? "ptr " : "";
913904 const char *const_str = instruction->lval.is_const ? "const " : "";
......@@ -987,6 +978,24 @@ static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instructi
987978 fprintf(irp->f, ")");
988979}
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
9911000static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
9921001 ir_print_prefix(irp, instruction);
......@@ -1263,12 +1272,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
12631272 case IrInstructionIdPtrTypeOf:
12641273 ir_print_ptr_type_of(irp, (IrInstructionPtrTypeOf *)instruction);
12651274 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;
12721275 case IrInstructionIdDeclRef:
12731276 ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction);
12741277 break;
......@@ -1302,6 +1305,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13021305 case IrInstructionIdTagType:
13031306 ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction);
13041307 break;
1308 case IrInstructionIdExport:
1309 ir_print_export(irp, (IrInstructionExport *)instruction);
1310 break;
13051311 }
13061312 fprintf(irp->f, "\n");
13071313}
src/parser.cpp+236-179
......@@ -632,27 +632,6 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m
632632 return node;
633633}
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
656635/*
657636CompTimeExpression(body) = "comptime" body
658637*/
......@@ -676,8 +655,8 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
676655}
677656
678657/*
679PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
680KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
658PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol))
659KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
681660*/
682661static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
683662 Token *token = &pc->tokens->at(*token_index);
......@@ -721,6 +700,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
721700 } else if (token->id == TokenIdKeywordContinue) {
722701 AstNode *node = ast_create_node(pc, NodeTypeContinue, token);
723702 *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 }
724709 return node;
725710 } else if (token->id == TokenIdKeywordUndefined) {
726711 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
740725 return node;
741726 } else if (token->id == TokenIdAtSign) {
742727 *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
744741 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
747744 AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token);
748745 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
751748 node->data.fn_call_expr.is_builtin = true;
752749
753750 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) {
755759 *token_index += 1;
756760 AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
757761 node->data.symbol_expr.symbol = token_buf(token);
758762 return node;
759763 }
760764
761 AstNode *goto_node = ast_parse_goto_expr(pc, token_index, false);
762 if (goto_node)
763 return goto_node;
764
765765 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
766766 if (grouped_expr_node) {
767767 return grouped_expr_node;
768768 }
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
775770 AstNode *array_type_node = ast_parse_array_type_expr(pc, token_index, false);
776771 if (array_type_node) {
777772 return array_type_node;
......@@ -791,13 +786,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
791786 if (container_decl)
792787 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
801789 if (!mandatory)
802790 return nullptr;
803791
......@@ -1483,7 +1471,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
14831471}
14841472
14851473/*
1486BreakExpression : "break" option(Expression)
1474BreakExpression = "break" option(":" Symbol) option(Expression)
14871475*/
14881476static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) {
14891477 Token *token = &pc->tokens->at(*token_index);
......@@ -1493,8 +1481,15 @@ static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) {
14931481 } else {
14941482 return nullptr;
14951483 }
1496
14971484 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
14981493 node->data.break_expr.expr = ast_parse_expression(pc, token_index, false);
14991494
15001495 return node;
......@@ -1534,38 +1529,20 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
15341529}
15351530
15361531/*
1537VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression
1532VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression
15381533*/
15391534static 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)
15411536{
15421537 Token *first_token = &pc->tokens->at(*token_index);
15431538 Token *var_token;
15441539
15451540 bool is_const;
1546 bool is_comptime;
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;
1541 if (first_token->id == TokenIdKeywordVar) {
15641542 is_const = false;
15651543 var_token = first_token;
15661544 *token_index += 1;
15671545 } else if (first_token->id == TokenIdKeywordConst) {
1568 is_comptime = false;
15691546 is_const = true;
15701547 var_token = first_token;
15711548 *token_index += 1;
......@@ -1577,7 +1554,8 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to
15771554
15781555 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;
15811559 node->data.variable_declaration.is_const = is_const;
15821560 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
16001578 next_token = &pc->tokens->at(*token_index);
16011579 }
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
16031589 if (next_token->id == TokenIdEq) {
16041590 *token_index += 1;
16051591 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
16121598 return node;
16131599}
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
16151645/*
16161646BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
16171647*/
......@@ -1638,35 +1668,53 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, size_t *token_index, bo
16381668}
16391669
16401670/*
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))
16421672*/
16431673static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1644 Token *first_token = &pc->tokens->at(*token_index);
1645 Token *while_token;
1674 size_t orig_token_index = *token_index;
16461675
1647 bool is_inline;
1648 if (first_token->id == TokenIdKeywordInline) {
1649 while_token = &pc->tokens->at(*token_index + 1);
1650 if (while_token->id == TokenIdKeywordWhile) {
1651 is_inline = true;
1652 *token_index += 2;
1676 Token *name_token = nullptr;
1677 Token *token = &pc->tokens->at(*token_index);
1678
1679 if (token->id == TokenIdSymbol) {
1680 *token_index += 1;
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);
16531686 } else if (mandatory) {
1654 ast_expect_token(pc, while_token, TokenIdKeywordWhile);
1687 ast_expect_token(pc, colon_token, TokenIdColon);
16551688 zig_unreachable();
16561689 } else {
1690 *token_index = orig_token_index;
16571691 return nullptr;
16581692 }
1659 } else if (first_token->id == TokenIdKeywordWhile) {
1660 while_token = first_token;
1661 is_inline = false;
1693 }
1694
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;
16621705 *token_index += 1;
16631706 } else if (mandatory) {
1664 ast_expect_token(pc, first_token, TokenIdKeywordWhile);
1707 ast_expect_token(pc, token, TokenIdKeywordWhile);
16651708 zig_unreachable();
16661709 } else {
1710 *token_index = orig_token_index;
16671711 return nullptr;
16681712 }
1713
16691714 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 }
16701718 node->data.while_expr.is_inline = is_inline;
16711719
16721720 ast_eat_token(pc, token_index, TokenIdLParen);
......@@ -1726,36 +1774,53 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) {
17261774}
17271775
17281776/*
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))
17301778*/
17311779static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1732 Token *first_token = &pc->tokens->at(*token_index);
1733 Token *for_token;
1780 size_t orig_token_index = *token_index;
17341781
1735 bool is_inline;
1736 if (first_token->id == TokenIdKeywordInline) {
1737 is_inline = true;
1738 for_token = &pc->tokens->at(*token_index + 1);
1739 if (for_token->id == TokenIdKeywordFor) {
1740 *token_index += 2;
1782 Token *name_token = nullptr;
1783 Token *token = &pc->tokens->at(*token_index);
1784
1785 if (token->id == TokenIdSymbol) {
1786 *token_index += 1;
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);
17411792 } else if (mandatory) {
1742 ast_expect_token(pc, first_token, TokenIdKeywordFor);
1793 ast_expect_token(pc, colon_token, TokenIdColon);
17431794 zig_unreachable();
17441795 } else {
1796 *token_index = orig_token_index;
17451797 return nullptr;
17461798 }
1747 } else if (first_token->id == TokenIdKeywordFor) {
1748 for_token = first_token;
1749 is_inline = false;
1799 }
1800
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;
17501811 *token_index += 1;
17511812 } else if (mandatory) {
1752 ast_expect_token(pc, first_token, TokenIdKeywordFor);
1813 ast_expect_token(pc, token, TokenIdKeywordFor);
17531814 zig_unreachable();
17541815 } else {
1816 *token_index = orig_token_index;
17551817 return nullptr;
17561818 }
17571819
17581820 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 }
17591824 node->data.for_expr.is_inline = is_inline;
17601825
17611826 ast_eat_token(pc, token_index, TokenIdLParen);
......@@ -2082,35 +2147,6 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
20822147 return nullptr;
20832148}
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
21142150static bool statement_terminates_without_semicolon(AstNode *node) {
21152151 switch (node->type) {
21162152 case NodeTypeIfBoolExpr:
......@@ -2135,7 +2171,6 @@ static bool statement_terminates_without_semicolon(AstNode *node) {
21352171 return node->data.defer.expr->type == NodeTypeBlock;
21362172 case NodeTypeSwitchExpr:
21372173 case NodeTypeBlock:
2138 case NodeTypeLabel:
21392174 return true;
21402175 default:
21412176 return false;
......@@ -2143,27 +2178,54 @@ static bool statement_terminates_without_semicolon(AstNode *node) {
21432178}
21442179
21452180/*
2146Block = "{" many(Statement) option(Expression) "}"
2147Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
2181Block = option(Symbol ":") "{" many(Statement) "}"
2182Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ExportDecl
21482183*/
21492184static 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;
21502188 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
21522206 if (last_token->id != TokenIdLBrace) {
21532207 if (mandatory) {
21542208 ast_expect_token(pc, last_token, TokenIdLBrace);
21552209 } else {
2210 *token_index = orig_token_index;
21562211 return nullptr;
21572212 }
21582213 }
21592214 *token_index += 1;
21602215
21612216 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
21632221 for (;;) {
2164 AstNode *statement_node = ast_parse_label(pc, token_index, false);
2165 if (!statement_node)
2166 statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate);
2222 last_token = &pc->tokens->at(*token_index);
2223 if (last_token->id == TokenIdRBrace) {
2224 *token_index += 1;
2225 return node;
2226 }
2227
2228 AstNode *statement_node = ast_parse_local_var_decl(pc, token_index);
21672229 if (!statement_node)
21682230 statement_node = ast_parse_defer_expr(pc, token_index);
21692231 if (!statement_node)
......@@ -2171,47 +2233,28 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
21712233 if (!statement_node)
21722234 statement_node = ast_parse_expression(pc, token_index, false);
21732235
2174 bool semicolon_expected = true;
2175 if (statement_node) {
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 }
2236 if (!statement_node) {
2237 ast_invalid_token_error(pc, last_token);
21862238 }
21872239
2188 node->data.block.last_statement_is_result_expression = statement_node && !(
2189 statement_node->type == NodeTypeLabel ||
2190 statement_node->type == NodeTypeDefer);
2240 node->data.block.statements.append(statement_node);
21912241
2192 last_token = &pc->tokens->at(*token_index);
2193 if (last_token->id == TokenIdRBrace) {
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);
2242 if (!statement_terminates_without_semicolon(statement_node)) {
2243 ast_eat_token(pc, token_index, TokenIdSemicolon);
22022244 }
22032245 }
22042246 zig_unreachable();
22052247}
22062248
22072249/*
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)
22092251*/
22102252static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
22112253 Token *first_token = &pc->tokens->at(*token_index);
22122254 Token *fn_token;
22132255
22142256 CallingConvention cc;
2257 bool is_extern = false;
22152258 if (first_token->id == TokenIdKeywordColdCC) {
22162259 *token_index += 1;
22172260 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
22242267 *token_index += 1;
22252268 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
22262269 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;
22272285 } else if (first_token->id == TokenIdKeywordFn) {
22282286 fn_token = first_token;
22292287 *token_index += 1;
......@@ -2238,6 +2296,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
22382296 AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
22392297 node->data.fn_proto.visib_mod = visib_mod;
22402298 node->data.fn_proto.cc = cc;
2299 node->data.fn_proto.is_extern = is_extern;
22412300
22422301 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
22592318 ast_eat_token(pc, token_index, TokenIdRParen);
22602319 next_token = &pc->tokens->at(*token_index);
22612320 }
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 }
22622329 if (next_token->id == TokenIdArrow) {
22632330 *token_index += 1;
22642331 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
22702337}
22712338
22722339/*
2273FnDef = option("inline" | "extern") FnProto Block
2340FnDef = option("inline" | "export") FnProto Block
22742341*/
22752342static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
22762343 Token *first_token = &pc->tokens->at(*token_index);
22772344 bool is_inline;
2278 bool is_extern;
2345 bool is_export;
22792346 if (first_token->id == TokenIdKeywordInline) {
22802347 *token_index += 1;
22812348 is_inline = true;
2282 is_extern = false;
2283 } else if (first_token->id == TokenIdKeywordExtern) {
2349 is_export = false;
2350 } else if (first_token->id == TokenIdKeywordExport) {
22842351 *token_index += 1;
2285 is_extern = true;
2352 is_export = true;
22862353 is_inline = false;
22872354 } else {
22882355 is_inline = false;
2289 is_extern = false;
2356 is_export = false;
22902357 }
22912358
22922359 AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, visib_mod);
22932360 if (!fn_proto) {
2294 if (is_inline || is_extern) {
2361 if (is_inline || is_export) {
22952362 *token_index -= 1;
22962363 }
22972364 return nullptr;
22982365 }
22992366
23002367 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
23032370 Token *semi_token = &pc->tokens->at(*token_index);
23042371 if (semi_token->id == TokenIdSemicolon) {
......@@ -2344,7 +2411,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
23442411 return fn_proto_node;
23452412 }
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);
23482415 if (var_decl_node) {
23492416 ast_eat_token(pc, token_index, TokenIdSemicolon);
23502417
......@@ -2447,9 +2514,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
24472514 if (visib_tok->id == TokenIdKeywordPub) {
24482515 *token_index += 1;
24492516 visib_mod = VisibModPub;
2450 } else if (visib_tok->id == TokenIdKeywordExport) {
2451 *token_index += 1;
2452 visib_mod = VisibModExport;
24532517 } else {
24542518 visib_mod = VisibModPrivate;
24552519 }
......@@ -2460,7 +2524,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
24602524 continue;
24612525 }
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);
24642528 if (var_decl_node) {
24652529 ast_eat_token(pc, token_index, TokenIdSemicolon);
24662530 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)
25532617
25542618/*
25552619TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl
2556TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
2620TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
25572621*/
25582622static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList<AstNode *> *top_level_decls) {
25592623 for (;;) {
......@@ -2580,9 +2644,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig
25802644 if (visib_tok->id == TokenIdKeywordPub) {
25812645 *token_index += 1;
25822646 visib_mod = VisibModPub;
2583 } else if (visib_tok->id == TokenIdKeywordExport) {
2584 *token_index += 1;
2585 visib_mod = VisibModExport;
25862647 } else {
25872648 visib_mod = VisibModPrivate;
25882649 }
......@@ -2605,7 +2666,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig
26052666 continue;
26062667 }
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);
26092670 if (var_decl_node) {
26102671 ast_eat_token(pc, token_index, TokenIdSemicolon);
26112672 top_level_decls->append(var_decl_node);
......@@ -2669,6 +2730,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
26692730 visit_field(&node->data.fn_proto.return_type, visit, context);
26702731 visit_node_list(&node->data.fn_proto.params, visit, context);
26712732 visit_field(&node->data.fn_proto.align_expr, visit, context);
2733 visit_field(&node->data.fn_proto.section_expr, visit, context);
26722734 break;
26732735 case NodeTypeFnDef:
26742736 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
26962758 visit_field(&node->data.variable_declaration.type, visit, context);
26972759 visit_field(&node->data.variable_declaration.expr, visit, context);
26982760 visit_field(&node->data.variable_declaration.align_expr, visit, context);
2761 visit_field(&node->data.variable_declaration.section_expr, visit, context);
26992762 break;
27002763 case NodeTypeErrorValueDecl:
27012764 // none
......@@ -2799,12 +2862,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
27992862 visit_field(&node->data.switch_range.start, visit, context);
28002863 visit_field(&node->data.switch_range.end, visit, context);
28012864 break;
2802 case NodeTypeLabel:
2803 // none
2804 break;
2805 case NodeTypeGoto:
2806 // none
2807 break;
28082865 case NodeTypeCompTime:
28092866 visit_field(&node->data.comptime_expr.expr, visit, context);
28102867 break;
src/tokenizer.cpp+2
......@@ -134,6 +134,7 @@ static const struct ZigKeyword zig_keywords[] = {
134134 {"packed", TokenIdKeywordPacked},
135135 {"pub", TokenIdKeywordPub},
136136 {"return", TokenIdKeywordReturn},
137 {"section", TokenIdKeywordSection},
137138 {"stdcallcc", TokenIdKeywordStdcallCC},
138139 {"struct", TokenIdKeywordStruct},
139140 {"switch", TokenIdKeywordSwitch},
......@@ -1533,6 +1534,7 @@ const char * token_name(TokenId id) {
15331534 case TokenIdKeywordPacked: return "packed";
15341535 case TokenIdKeywordPub: return "pub";
15351536 case TokenIdKeywordReturn: return "return";
1537 case TokenIdKeywordSection: return "section";
15361538 case TokenIdKeywordStdcallCC: return "stdcallcc";
15371539 case TokenIdKeywordStruct: return "struct";
15381540 case TokenIdKeywordSwitch: return "switch";
src/tokenizer.hpp+1
......@@ -47,6 +47,7 @@ enum TokenId {
4747 TokenIdFloatLiteral,
4848 TokenIdIntLiteral,
4949 TokenIdKeywordAlign,
50 TokenIdKeywordSection,
5051 TokenIdKeywordAnd,
5152 TokenIdKeywordAsm,
5253 TokenIdKeywordBreak,
src/translate_c.cpp+185-244
......@@ -73,7 +73,7 @@ struct Context {
7373 ImportTableEntry *import;
7474 ZigList<ErrorMsg *> *errors;
7575 VisibMod visib_mod;
76 VisibMod export_visib_mod;
76 bool want_export;
7777 AstNode *root;
7878 HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table;
7979 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table;
......@@ -104,10 +104,8 @@ static TransScopeRoot *trans_scope_root_create(Context *c);
104104static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope);
105105static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope);
106106static 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
109108static TransScopeBlock *trans_scope_block_find(TransScope *scope);
110static TransScopeSwitch *trans_scope_switch_find(TransScope *scope);
111109
112110static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl);
113111static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl);
......@@ -173,6 +171,28 @@ static AstNode * trans_create_node(Context *c, NodeType id) {
173171 return node;
174172}
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
176196static AstNode *trans_create_node_float_lit(Context *c, double value) {
177197 AstNode *node = trans_create_node(c, NodeTypeFloatLiteral);
178198 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
257277 return node;
258278}
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
272280static AstNode *trans_create_node_bool(Context *c, bool value) {
273281 AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral);
274282 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
378386
379387 AstNode *block = trans_create_node(c, NodeTypeBlock);
380388 block->data.block.statements.resize(1);
381 block->data.block.statements.items[0] = fn_call_node;
382 block->data.block.last_statement_is_result_expression = true;
389 block->data.block.statements.items[0] = trans_create_node_return(c, fn_call_node);
383390
384391 fn_def->data.fn_def.body = block;
385392 return fn_def;
......@@ -1149,13 +1156,15 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco
11491156 } else {
11501157 // worst case
11511158 // c: lhs = rhs
1152 // zig: {
1159 // zig: x: {
11531160 // zig: const _tmp = rhs;
11541161 // zig: lhs = _tmp;
1155 // zig: _tmp
1162 // zig: break :x _tmp
11561163 // zig: }
11571164
11581165 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
11601169 // const _tmp = rhs;
11611170 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
11721181 trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign,
11731182 trans_create_node_symbol(c, tmp_var_name)));
11741183
1175 // _tmp
1176 child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
1177 child_scope->node->data.block.last_statement_is_result_expression = true;
1184 // break :x _tmp
1185 AstNode *tmp_symbol_node = trans_create_node_symbol(c, tmp_var_name);
1186 child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, tmp_symbol_node));
11781187
11791188 return child_scope->node;
11801189 }
......@@ -1279,6 +1288,9 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
12791288 case BO_Comma:
12801289 {
12811290 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
12821294 AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue);
12831295 if (lhs == nullptr)
12841296 return nullptr;
......@@ -1287,9 +1299,7 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
12871299 AstNode *rhs = trans_expr(c, result_used, &scope_block->base, stmt->getRHS(), TransRValue);
12881300 if (rhs == nullptr)
12891301 return nullptr;
1290 scope_block->node->data.block.statements.append(maybe_suppress_result(c, result_used, rhs));
1291
1292 scope_block->node->data.block.last_statement_is_result_expression = true;
1302 scope_block->node->data.block.statements.append(trans_create_node_break(c, label_name, maybe_suppress_result(c, result_used, rhs)));
12931303 return scope_block->node;
12941304 }
12951305 case BO_MulAssign:
......@@ -1329,14 +1339,16 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
13291339 } else {
13301340 // need more complexity. worst case, this looks like this:
13311341 // c: lhs >>= rhs
1332 // zig: {
1342 // zig: x: {
13331343 // zig: const _ref = &lhs;
13341344 // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs));
1335 // zig: *_ref
1345 // zig: break :x *_ref
13361346 // zig: }
13371347 // where u5 is the appropriate type
13381348
13391349 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
13411353 // const _ref = &lhs;
13421354 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
13781390 child_scope->node->data.block.statements.append(assign_statement);
13791391
13801392 if (result_used == ResultUsedYes) {
1381 // *_ref
1393 // break :x *_ref
13821394 child_scope->node->data.block.statements.append(
1383 trans_create_node_prefix_op(c, PrefixOpDereference,
1384 trans_create_node_symbol(c, tmp_var_name)));
1385 child_scope->node->data.block.last_statement_is_result_expression = true;
1395 trans_create_node_break(c, label_name,
1396 trans_create_node_prefix_op(c, PrefixOpDereference,
1397 trans_create_node_symbol(c, tmp_var_name))));
13861398 }
13871399
13881400 return child_scope->node;
......@@ -1403,13 +1415,15 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
14031415 } else {
14041416 // need more complexity. worst case, this looks like this:
14051417 // c: lhs += rhs
1406 // zig: {
1418 // zig: x: {
14071419 // zig: const _ref = &lhs;
14081420 // zig: *_ref = *_ref + rhs;
1409 // zig: *_ref
1421 // zig: break :x *_ref
14101422 // zig: }
14111423
14121424 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
14141428 // const _ref = &lhs;
14151429 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,
14361450 rhs));
14371451 child_scope->node->data.block.statements.append(assign_statement);
14381452
1439 // *_ref
1453 // break :x *_ref
14401454 child_scope->node->data.block.statements.append(
1441 trans_create_node_prefix_op(c, PrefixOpDereference,
1442 trans_create_node_symbol(c, tmp_var_name)));
1443 child_scope->node->data.block.last_statement_is_result_expression = true;
1455 trans_create_node_break(c, label_name,
1456 trans_create_node_prefix_op(c, PrefixOpDereference,
1457 trans_create_node_symbol(c, tmp_var_name))));
14441458
14451459 return child_scope->node;
14461460 }
......@@ -1735,13 +1749,15 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
17351749 }
17361750 // worst case
17371751 // c: expr++
1738 // zig: {
1752 // zig: x: {
17391753 // zig: const _ref = &expr;
17401754 // zig: const _tmp = *_ref;
17411755 // zig: *_ref += 1;
1742 // zig: _tmp
1756 // zig: break :x _tmp
17431757 // zig: }
17441758 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
17461762 // const _ref = &expr;
17471763 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
17671783 trans_create_node_unsigned(c, 1));
17681784 child_scope->node->data.block.statements.append(assign_statement);
17691785
1770 // _tmp
1771 child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
1772 child_scope->node->data.block.last_statement_is_result_expression = true;
1786 // break :x _tmp
1787 child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, trans_create_node_symbol(c, tmp_var_name)));
17731788
17741789 return child_scope->node;
17751790}
......@@ -1790,12 +1805,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
17901805 }
17911806 // worst case
17921807 // c: ++expr
1793 // zig: {
1808 // zig: x: {
17941809 // zig: const _ref = &expr;
17951810 // zig: *_ref += 1;
1796 // zig: *_ref
1811 // zig: break :x *_ref
17971812 // zig: }
17981813 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
18001817 // const _ref = &expr;
18011818 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
18141831 trans_create_node_unsigned(c, 1));
18151832 child_scope->node->data.block.statements.append(assign_statement);
18161833
1817 // *_ref
1834 // break :x *_ref
18181835 AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
18191836 trans_create_node_symbol(c, ref_var_name));
1820 child_scope->node->data.block.statements.append(deref_expr);
1821 child_scope->node->data.block.last_statement_is_result_expression = true;
1837 child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));
18221838
18231839 return child_scope->node;
18241840}
......@@ -2374,145 +2390,6 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt
23742390 return while_scope->node;
23752391}
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
25162393static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForStmt *stmt) {
25172394 AstNode *loop_block_node;
25182395 TransScopeWhile *while_scope;
......@@ -2590,8 +2467,7 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt
25902467 if (cur_scope->id == TransScopeIdWhile) {
25912468 return trans_create_node(c, NodeTypeBreak);
25922469 } else if (cur_scope->id == TransScopeIdSwitch) {
2593 TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope;
2594 return trans_create_node_goto(c, switch_scope->end_label_name);
2470 zig_panic("TODO");
25952471 }
25962472 cur_scope = cur_scope->parent;
25972473 }
......@@ -2691,12 +2567,14 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
26912567 return wrap_stmt(out_node, out_child_scope, scope,
26922568 trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue));
26932569 case Stmt::SwitchStmtClass:
2694 return wrap_stmt(out_node, out_child_scope, scope,
2695 trans_switch_stmt(c, scope, (const SwitchStmt *)stmt));
2570 emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass");
2571 return ErrorUnexpected;
26962572 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;
26982575 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;
27002578 case Stmt::NoStmtClass:
27012579 emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass");
27022580 return ErrorUnexpected;
......@@ -3246,7 +3124,8 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
32463124
32473125 StorageClass sc = fn_decl->getStorageClass();
32483126 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;
32503129 } else if (sc == SC_Extern || sc == SC_Static) {
32513130 proto_node->data.fn_proto.visib_mod = c->visib_mod;
32523131 } else if (sc == SC_PrivateExtern) {
......@@ -3865,14 +3744,6 @@ static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scop
38653744 return result;
38663745}
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
38763747static TransScopeBlock *trans_scope_block_find(TransScope *scope) {
38773748 while (scope != nullptr) {
38783749 if (scope->id == TransScopeIdBlock) {
......@@ -3883,16 +3754,6 @@ static TransScopeBlock *trans_scope_block_find(TransScope *scope) {
38833754 return nullptr;
38843755}
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
38963757static void render_aliases(Context *c) {
38973758 for (size_t i = 0; i < c->aliases.length; i += 1) {
38983759 Alias *alias = &c->aliases.at(i);
......@@ -4003,6 +3864,10 @@ static void render_macros(Context *c) {
40033864 }
40043865}
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
40063871static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) {
40073872 CTok *tok = &ctok->tokens.at(*tok_i);
40083873 if (tok->id == CTokIdNumLitInt) {
......@@ -4030,7 +3895,7 @@ static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, b
40303895 return nullptr;
40313896}
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) {
40343899 CTok *tok = &ctok->tokens.at(*tok_i);
40353900 switch (tok->id) {
40363901 case CTokIdCharLit:
......@@ -4047,55 +3912,131 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {
40473912 return parse_ctok_num_lit(c, ctok, tok_i, false);
40483913 case CTokIdSymbol:
40493914 {
4050 bool need_symbol = false;
4051 CTokId curr_id = CTokIdSymbol;
3915 *tok_i += 1;
40523916 Buf *symbol_name = buf_create_from_buf(&tok->data.symbol);
4053 AstNode *curr_node = 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;
3917 return trans_create_node_symbol(c, symbol_name);
40773918 }
40783919 case CTokIdLParen:
40793920 {
40803921 *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
40833927 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) {
40853940 return nullptr;
40863941 }
40873942 *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);
40893973 }
40903974 case CTokIdDot:
40913975 case CTokIdEOF:
40923976 case CTokIdRParen:
3977 case CTokIdAsterisk:
3978 case CTokIdBang:
3979 case CTokIdTilde:
40933980 // not able to make sense of this
40943981 return nullptr;
40953982 }
40963983 zig_unreachable();
40973984}
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
40994040static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) {
41004041 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
41084049 assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name));
41094050 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);
41124053 if (result_node == nullptr) {
41134054 return;
41144055 }
......@@ -4189,10 +4130,10 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
41894130 c->errors = errors;
41904131 if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) {
41914132 c->visib_mod = VisibModPub;
4192 c->export_visib_mod = VisibModPub;
4133 c->want_export = false;
41934134 } else {
41944135 c->visib_mod = VisibModPub;
4195 c->export_visib_mod = VisibModExport;
4136 c->want_export = true;
41964137 }
41974138 c->decl_table.init(8);
41984139 c->macro_table.init(8);
src/zig_llvm.cpp+10-3
......@@ -175,12 +175,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
175175
176176
177177LLVMValueRef 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)
179179{
180180 CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name);
181181 call_inst->setCallingConv(CC);
182 if (always_inline) {
183 call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline);
182 switch (fn_inline) {
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;
184191 }
185192 return wrap(unwrap(B)->Insert(call_inst));
186193}
src/zig_llvm.hpp+6-1
......@@ -45,8 +45,13 @@ enum ZigLLVM_EmitOutputType {
4545bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
4646 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};
4853LLVMValueRef 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
5156LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
5257 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
std/array_list.zig+24-14
......@@ -3,42 +3,46 @@ const assert = debug.assert;
33const mem = @import("mem.zig");
44const Allocator = mem.Allocator;
55
6pub fn ArrayList(comptime T: type) -> type{
7 struct {
6pub fn ArrayList(comptime T: type) -> type {
7 return AlignedArrayList(T, @alignOf(T));
8}
9
10pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
11 return struct {
812 const Self = this;
913
1014 /// Use toSlice instead of slicing this directly, because if you don't
1115 /// specify the end position of the slice, this will potentially give
1216 /// you uninitialized memory.
13 items: []T,
17 items: []align(A) T,
1418 len: usize,
1519 allocator: &Allocator,
1620
1721 /// Deinitialize with `deinit` or use `toOwnedSlice`.
1822 pub fn init(allocator: &Allocator) -> Self {
19 Self {
20 .items = []T{},
23 return Self {
24 .items = []align(A) T{},
2125 .len = 0,
2226 .allocator = allocator,
23 }
27 };
2428 }
2529
2630 pub fn deinit(l: &Self) {
2731 l.allocator.free(l.items);
2832 }
2933
30 pub fn toSlice(l: &Self) -> []T {
34 pub fn toSlice(l: &Self) -> []align(A) T {
3135 return l.items[0..l.len];
3236 }
3337
34 pub fn toSliceConst(l: &const Self) -> []const T {
38 pub fn toSliceConst(l: &const Self) -> []align(A) const T {
3539 return l.items[0..l.len];
3640 }
3741
3842 /// ArrayList takes ownership of the passed in slice. The slice must have been
3943 /// allocated with `allocator`.
4044 /// 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 {
4246 return Self {
4347 .items = slice,
4448 .len = slice.len,
......@@ -47,9 +51,9 @@ pub fn ArrayList(comptime T: type) -> type{
4751 }
4852
4953 /// 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 {
5155 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);
5357 *self = init(allocator);
5458 return result;
5559 }
......@@ -59,7 +63,7 @@ pub fn ArrayList(comptime T: type) -> type{
5963 *new_item_ptr = *item;
6064 }
6165
62 pub fn appendSlice(l: &Self, items: []const T) -> %void {
66 pub fn appendSlice(l: &Self, items: []align(A) const T) -> %void {
6367 %return l.ensureCapacity(l.len + items.len);
6468 mem.copy(T, l.items[l.len..], items);
6569 l.len += items.len;
......@@ -82,7 +86,7 @@ pub fn ArrayList(comptime T: type) -> type{
8286 better_capacity += better_capacity / 2 + 8;
8387 if (better_capacity >= new_capacity) break;
8488 }
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);
8690 }
8791
8892 pub fn addOne(l: &Self) -> %&T {
......@@ -97,7 +101,13 @@ pub fn ArrayList(comptime T: type) -> type{
97101 self.len -= 1;
98102 return self.items[self.len];
99103 }
100 }
104
105 pub fn popOrNull(self: &Self) -> ?T {
106 if (self.len == 0)
107 return null;
108 return self.pop();
109 }
110 };
101111}
102112
103113test "basic ArrayList test" {
std/base64.zig+1-1
......@@ -193,7 +193,7 @@ pub const Base64DecoderWithIgnore = struct {
193193 /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound.
194194 /// Returns the number of bytes writen to dest.
195195 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
198198 var src_cursor: usize = 0;
199199 var dest_cursor: usize = 0;
std/buf_map.zig+5
......@@ -42,6 +42,11 @@ pub const BufMap = struct {
4242 }
4343 }
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
4550 pub fn delete(self: &BufMap, key: []const u8) {
4651 const entry = self.hash_map.remove(key) ?? return;
4752 self.free(entry.key);
std/buffer.zig+11-3
......@@ -30,9 +30,9 @@ pub const Buffer = struct {
3030 /// * ::replaceContentsBuffer
3131 /// * ::resize
3232 pub fn initNull(allocator: &Allocator) -> Buffer {
33 Buffer {
33 return Buffer {
3434 .list = ArrayList(u8).init(allocator),
35 }
35 };
3636 }
3737
3838 /// Must deinitialize with deinit.
......@@ -98,14 +98,17 @@ pub const Buffer = struct {
9898 mem.copy(u8, self.list.toSlice()[old_len..], m);
9999 }
100100
101 // TODO: remove, use OutStream for this
101102 pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) -> %void {
102103 return fmt.format(self, append, format, args);
103104 }
104105
106 // TODO: remove, use OutStream for this
105107 pub fn appendByte(self: &Buffer, byte: u8) -> %void {
106108 return self.appendByteNTimes(byte, 1);
107109 }
108110
111 // TODO: remove, use OutStream for this
109112 pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) -> %void {
110113 var prev_size: usize = self.len();
111114 %return self.resize(prev_size + count);
......@@ -117,7 +120,7 @@ pub const Buffer = struct {
117120 }
118121
119122 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);
121124 }
122125
123126 pub fn startsWith(self: &const Buffer, m: []const u8) -> bool {
......@@ -136,6 +139,11 @@ pub const Buffer = struct {
136139 %return self.resize(m.len);
137140 mem.copy(u8, self.list.toSlice(), m);
138141 }
142
143 /// For passing to C functions.
144 pub fn ptr(self: &const Buffer) -> &u8 {
145 return self.list.items.ptr;
146 }
139147};
140148
141149test "simple Buffer" {
std/build.zig+102-32
......@@ -221,11 +221,11 @@ pub const Builder = struct {
221221 }
222222
223223 pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version {
224 Version {
224 return Version {
225225 .major = major,
226226 .minor = minor,
227227 .patch = patch,
228 }
228 };
229229 }
230230
231231 pub fn addCIncludePath(self: &Builder, path: []const u8) {
......@@ -432,16 +432,16 @@ pub const Builder = struct {
432432 const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false;
433433 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)
436436 builtin.Mode.ReleaseSafe
437 } else if (release_fast and !release_safe) {
437 else if (release_fast and !release_safe)
438438 builtin.Mode.ReleaseFast
439 } else if (!release_fast and !release_safe) {
439 else if (!release_fast and !release_safe)
440440 builtin.Mode.Debug
441 } else {
441 else x: {
442442 warn("Both -Drelease-safe and -Drelease-fast specified");
443443 self.markInvalidUserInput();
444 builtin.Mode.Debug
444 break :x builtin.Mode.Debug;
445445 };
446446 self.release_mode = mode;
447447 return mode;
......@@ -506,7 +506,7 @@ pub const Builder = struct {
506506 }
507507
508508 fn typeToEnum(comptime T: type) -> TypeId {
509 switch (@typeId(T)) {
509 return switch (@typeId(T)) {
510510 builtin.TypeId.Int => TypeId.Int,
511511 builtin.TypeId.Float => TypeId.Float,
512512 builtin.TypeId.Bool => TypeId.Bool,
......@@ -515,7 +515,7 @@ pub const Builder = struct {
515515 []const []const u8 => TypeId.List,
516516 else => @compileError("Unsupported type: " ++ @typeName(T)),
517517 },
518 }
518 };
519519 }
520520
521521 fn markInvalidUserInput(self: &Builder) {
......@@ -590,8 +590,7 @@ pub const Builder = struct {
590590
591591 return error.UncleanExit;
592592 },
593 };
594
593 }
595594 }
596595
597596 pub fn makePath(self: &Builder, path: []const u8) -> %void {
......@@ -662,13 +661,70 @@ pub const Builder = struct {
662661 if (builtin.environ == builtin.Environ.msvc) {
663662 return "cl.exe";
664663 } else {
665 return os.getEnvVarOwned(self.allocator, "CC") %% |err| {
666 if (err == error.EnvironmentVariableNotFound) {
664 return os.getEnvVarOwned(self.allocator, "CC") %% |err|
665 if (err == error.EnvironmentVariableNotFound)
667666 ([]const u8)("cc")
668 } else {
669 debug.panic("Unable to get environment variable: {}", err);
667 else
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;
670679 }
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 },
672728 }
673729 }
674730};
......@@ -755,6 +811,7 @@ pub const LibExeObjStep = struct {
755811 is_zig: bool,
756812 cflags: ArrayList([]const u8),
757813 include_dirs: ArrayList([]const u8),
814 lib_paths: ArrayList([]const u8),
758815 disable_libc: bool,
759816 frameworks: BufSet,
760817
......@@ -844,7 +901,7 @@ pub const LibExeObjStep = struct {
844901 .kind = kind,
845902 .root_src = root_src,
846903 .name = name,
847 .target = Target { .Native = {} },
904 .target = Target.Native,
848905 .linker_script = null,
849906 .link_libs = BufSet.init(builder.allocator),
850907 .frameworks = BufSet.init(builder.allocator),
......@@ -865,6 +922,7 @@ pub const LibExeObjStep = struct {
865922 .cflags = ArrayList([]const u8).init(builder.allocator),
866923 .source_files = undefined,
867924 .include_dirs = ArrayList([]const u8).init(builder.allocator),
925 .lib_paths = ArrayList([]const u8).init(builder.allocator),
868926 .object_src = undefined,
869927 .disable_libc = true,
870928 };
......@@ -879,7 +937,7 @@ pub const LibExeObjStep = struct {
879937 .kind = kind,
880938 .version = *version,
881939 .static = static,
882 .target = Target { .Native = {} },
940 .target = Target.Native,
883941 .cflags = ArrayList([]const u8).init(builder.allocator),
884942 .source_files = ArrayList([]const u8).init(builder.allocator),
885943 .object_files = ArrayList([]const u8).init(builder.allocator),
......@@ -888,6 +946,7 @@ pub const LibExeObjStep = struct {
888946 .frameworks = BufSet.init(builder.allocator),
889947 .full_path_libs = ArrayList([]const u8).init(builder.allocator),
890948 .include_dirs = ArrayList([]const u8).init(builder.allocator),
949 .lib_paths = ArrayList([]const u8).init(builder.allocator),
891950 .output_path = null,
892951 .out_filename = undefined,
893952 .major_only_filename = undefined,
......@@ -1018,11 +1077,10 @@ pub const LibExeObjStep = struct {
10181077 }
10191078
10201079 pub fn getOutputPath(self: &LibExeObjStep) -> []const u8 {
1021 if (self.output_path) |output_path| {
1080 return if (self.output_path) |output_path|
10221081 output_path
1023 } else {
1024 %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename)
1025 }
1082 else
1083 %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename);
10261084 }
10271085
10281086 pub fn setOutputHPath(self: &LibExeObjStep, file_path: []const u8) {
......@@ -1035,11 +1093,10 @@ pub const LibExeObjStep = struct {
10351093 }
10361094
10371095 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|
10391097 output_h_path
1040 } else {
1041 %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename)
1042 }
1098 else
1099 %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename);
10431100 }
10441101
10451102 pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) {
......@@ -1069,11 +1126,14 @@ pub const LibExeObjStep = struct {
10691126 %%self.include_dirs.append(self.builder.cache_root);
10701127 }
10711128
1072 // TODO put include_dirs in zig command line
10731129 pub fn addIncludeDir(self: &LibExeObjStep, path: []const u8) {
10741130 %%self.include_dirs.append(path);
10751131 }
10761132
1133 pub fn addLibPath(self: &LibExeObjStep, path: []const u8) {
1134 %%self.lib_paths.append(path);
1135 }
1136
10771137 pub fn addPackagePath(self: &LibExeObjStep, name: []const u8, pkg_index_path: []const u8) {
10781138 assert(self.is_zig);
10791139
......@@ -1222,6 +1282,11 @@ pub const LibExeObjStep = struct {
12221282 %%zig_args.append("--pkg-end");
12231283 }
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
12251290 for (builder.include_paths.toSliceConst()) |include_path| {
12261291 %%zig_args.append("-isystem");
12271292 %%zig_args.append(builder.pathFromRoot(include_path));
......@@ -1232,6 +1297,11 @@ pub const LibExeObjStep = struct {
12321297 %%zig_args.append(rpath);
12331298 }
12341299
1300 for (self.lib_paths.toSliceConst()) |lib_path| {
1301 %%zig_args.append("--library-path");
1302 %%zig_args.append(lib_path);
1303 }
1304
12351305 for (builder.lib_paths.toSliceConst()) |lib_path| {
12361306 %%zig_args.append("--library-path");
12371307 %%zig_args.append(lib_path);
......@@ -1544,7 +1614,7 @@ pub const TestStep = struct {
15441614
15451615 pub fn init(builder: &Builder, root_src: []const u8) -> TestStep {
15461616 const step_name = builder.fmt("test {}", root_src);
1547 TestStep {
1617 return TestStep {
15481618 .step = Step.init(step_name, builder.allocator, make),
15491619 .builder = builder,
15501620 .root_src = root_src,
......@@ -1555,7 +1625,7 @@ pub const TestStep = struct {
15551625 .link_libs = BufSet.init(builder.allocator),
15561626 .target = Target { .Native = {} },
15571627 .exec_cmd_args = null,
1558 }
1628 };
15591629 }
15601630
15611631 pub fn setVerbose(self: &TestStep, value: bool) {
......@@ -1862,16 +1932,16 @@ pub const Step = struct {
18621932 done_flag: bool,
18631933
18641934 pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)->%void) -> Step {
1865 Step {
1935 return Step {
18661936 .name = name,
18671937 .makeFn = makeFn,
18681938 .dependencies = ArrayList(&Step).init(allocator),
18691939 .loop_flag = false,
18701940 .done_flag = false,
1871 }
1941 };
18721942 }
18731943 pub fn initNoOp(name: []const u8, allocator: &Allocator) -> Step {
1874 init(name, allocator, makeNoOp)
1944 return init(name, allocator, makeNoOp);
18751945 }
18761946
18771947 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;
4848pub extern "c" fn malloc(usize) -> ?&c_void;
4949pub extern "c" fn realloc(&c_void, usize) -> ?&c_void;
5050pub 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 {
1717 return -1;
1818 } else {
1919 return 0;
20 };
20 }
2121}
2222
2323pub fn toSliceConst(str: &const u8) -> []const u8 {
std/debug.zig+130-84
......@@ -32,7 +32,7 @@ fn getStderrStream() -> %&io.OutStream {
3232 const st = &stderr_file_out_stream.stream;
3333 stderr_stream = st;
3434 return st;
35 };
35 }
3636}
3737
3838/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
......@@ -52,9 +52,9 @@ pub fn assert(ok: bool) {
5252 // we insert an explicit call to @panic instead of unreachable.
5353 // TODO we should use `assertOrPanic` in tests and remove this logic.
5454 if (builtin.is_test) {
55 @panic("assertion failure")
55 @panic("assertion failure");
5656 } else {
57 unreachable // assertion failure
57 unreachable; // assertion failure
5858 }
5959 }
6060}
......@@ -96,8 +96,6 @@ const WHITE = "\x1b[37;1m";
9696const DIM = "\x1b[2m";
9797const RESET = "\x1b[0m";
9898
99pub var user_main_fn: ?fn() -> %void = null;
100
10199error PathNotFound;
102100error InvalidDebugInfo;
103101
......@@ -113,6 +111,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
113111 .debug_abbrev = undefined,
114112 .debug_str = undefined,
115113 .debug_line = undefined,
114 .debug_ranges = null,
116115 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
117116 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
118117 };
......@@ -127,6 +126,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
127126 st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
128127 st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
129128 st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
129 st.debug_ranges = (%return st.elf.findSection(".debug_ranges"));
130130 %return scanAllCompileUnits(st);
131131
132132 var ignored_count: usize = 0;
......@@ -144,7 +144,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
144144 // at compile time. I'll call it issue #313
145145 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) %% {
148148 %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
149149 return_address);
150150 continue;
......@@ -175,7 +175,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
175175 return_address, compile_unit_name);
176176 },
177177 else => return err,
178 };
178 }
179179 }
180180 },
181181 builtin.ObjectFormat.coff => {
......@@ -233,6 +233,7 @@ const ElfStackTrace = struct {
233233 debug_abbrev: &elf.SectionHeader,
234234 debug_str: &elf.SectionHeader,
235235 debug_line: &elf.SectionHeader,
236 debug_ranges: ?&elf.SectionHeader,
236237 abbrev_table_list: ArrayList(AbbrevTableHeader),
237238 compile_unit_list: ArrayList(CompileUnit),
238239
......@@ -333,6 +334,15 @@ const Die = struct {
333334 };
334335 }
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
336346 fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 {
337347 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
338348 return switch (*form_value) {
......@@ -347,7 +357,7 @@ const Die = struct {
347357 FormValue.String => |value| value,
348358 FormValue.StrPtr => |offset| getString(st, offset),
349359 else => error.InvalidDebugInfo,
350 }
360 };
351361 }
352362};
353363
......@@ -393,7 +403,7 @@ const LineNumberProgram = struct {
393403 pub fn init(is_stmt: bool, include_dirs: []const []const u8,
394404 file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
395405 {
396 LineNumberProgram {
406 return LineNumberProgram {
397407 .address = 0,
398408 .file = 1,
399409 .line = 1,
......@@ -411,7 +421,7 @@ const LineNumberProgram = struct {
411421 .prev_is_stmt = undefined,
412422 .prev_basic_block = undefined,
413423 .prev_end_sequence = undefined,
414 }
424 };
415425 }
416426
417427 pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
......@@ -420,14 +430,11 @@ const LineNumberProgram = struct {
420430 return error.MissingDebugInfo;
421431 } else if (self.prev_file - 1 >= self.file_entries.len) {
422432 return error.InvalidDebugInfo;
423 } else {
424 &self.file_entries.items[self.prev_file - 1]
425 };
433 } else &self.file_entries.items[self.prev_file - 1];
434
426435 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
427436 return error.InvalidDebugInfo;
428 } else {
429 self.include_dirs[file_entry.dir_index]
430 };
437 } else self.include_dirs[file_entry.dir_index];
431438 const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
432439 %defer self.file_entries.allocator.free(file_name);
433440 return LineInfo {
......@@ -484,28 +491,21 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size:
484491}
485492
486493fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
487 FormValue { .Const = Constant {
494 return FormValue { .Const = Constant {
488495 .signed = signed,
489496 .payload = %return readAllocBytes(allocator, in_stream, size),
490 }}
497 }};
491498}
492499
493500fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
494 return if (is_64) {
495 %return in_stream.readIntLe(u64)
496 } else {
497 u64(%return in_stream.readIntLe(u32))
498 };
501 return if (is_64) %return in_stream.readIntLe(u64)
502 else u64(%return in_stream.readIntLe(u32)) ;
499503}
500504
501505fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
502 return if (@sizeOf(usize) == 4) {
503 u64(%return in_stream.readIntLe(u32))
504 } else if (@sizeOf(usize) == 8) {
505 %return in_stream.readIntLe(u64)
506 } else {
507 unreachable;
508 };
506 return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32))
507 else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64)
508 else unreachable;
509509}
510510
511511fn 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
524524 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
525525 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
526526 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
527 DW.FORM_block => {
527 DW.FORM_block => x: {
528528 const block_len = %return readULeb128(in_stream);
529 parseFormValueBlockLen(allocator, in_stream, block_len)
529 return parseFormValueBlockLen(allocator, in_stream, block_len);
530530 },
531531 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
532532 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
535535 DW.FORM_udata, DW.FORM_sdata => {
536536 const block_len = %return readULeb128(in_stream);
537537 const signed = form_id == DW.FORM_sdata;
538 parseFormValueConstant(allocator, in_stream, signed, block_len)
538 return parseFormValueConstant(allocator, in_stream, signed, block_len);
539539 },
540540 DW.FORM_exprloc => {
541541 const size = %return readULeb128(in_stream);
......@@ -552,7 +552,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
552552 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
553553 DW.FORM_ref_udata => {
554554 const ref_len = %return readULeb128(in_stream);
555 parseFormValueRefLen(allocator, in_stream, ref_len)
555 return parseFormValueRefLen(allocator, in_stream, ref_len);
556556 },
557557
558558 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
562562 DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
563563 DW.FORM_indirect => {
564564 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);
566566 },
567567 else => error.InvalidDebugInfo,
568 }
568 };
569569}
570570
571571fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
......@@ -842,11 +842,9 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
842842 const version = %return in_stream.readInt(st.elf.endian, u16);
843843 if (version < 2 or version > 5) return error.InvalidDebugInfo;
844844
845 const debug_abbrev_offset = if (is_64) {
846 %return in_stream.readInt(st.elf.endian, u64)
847 } else {
848 %return in_stream.readInt(st.elf.endian, u32)
849 };
845 const debug_abbrev_offset =
846 if (is_64) %return in_stream.readInt(st.elf.endian, u64)
847 else %return in_stream.readInt(st.elf.endian, u32);
850848
851849 const address_size = %return in_stream.readByte();
852850 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
......@@ -862,28 +860,28 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
862860 if (compile_unit_die.tag_id != DW.TAG_compile_unit)
863861 return error.InvalidDebugInfo;
864862
865 const pc_range = {
863 const pc_range = x: {
866864 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
867865 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
868866 const pc_end = switch (*high_pc_value) {
869867 FormValue.Address => |value| value,
870 FormValue.Const => |value| {
868 FormValue.Const => |value| b: {
871869 const offset = %return value.asUnsignedLe();
872 low_pc + offset
870 break :b (low_pc + offset);
873871 },
874872 else => return error.InvalidDebugInfo,
875873 };
876 PcRange {
874 break :x PcRange {
877875 .start = low_pc,
878876 .end = pc_end,
879 }
877 };
880878 } else {
881 null
879 break :x null;
882880 }
883881 } else |err| {
884882 if (err != error.MissingDebugInfo)
885883 return err;
886 null
884 break :x null;
887885 }
888886 };
889887
......@@ -900,25 +898,51 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
900898 }
901899}
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;
904904 for (st.compile_unit_list.toSlice()) |*compile_unit| {
905905 if (compile_unit.pc_range) |range| {
906906 if (target_address >= range.start and target_address < range.end)
907907 return compile_unit;
908908 }
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 }
909933 }
910 return null;
934 return error.MissingDebugInfo;
911935}
912936
913937fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
914938 const first_32_bits = %return in_stream.readIntLe(u32);
915939 *is_64 = (first_32_bits == 0xffffffff);
916 return if (*is_64) {
917 %return in_stream.readIntLe(u64)
940 if (*is_64) {
941 return in_stream.readIntLe(u64);
918942 } else {
919943 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
920 u64(first_32_bits)
921 };
944 return u64(first_32_bits);
945 }
922946}
923947
924948fn readULeb128(in_stream: &io.InStream) -> %u64 {
......@@ -965,40 +989,62 @@ fn readILeb128(in_stream: &io.InStream) -> %i64 {
965989 }
966990}
967991
968pub const global_allocator = &global_allocator_state;
969var global_allocator_state = mem.Allocator {
970 .allocFn = globalAlloc,
971 .reallocFn = globalRealloc,
972 .freeFn = globalFree,
973};
992pub const global_allocator = &global_fixed_allocator.allocator;
993var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);
994var global_allocator_mem: [100 * 1024]u8 = undefined;
974995
975var some_mem: [100 * 1024]u8 = undefined;
976var some_mem_index: usize = 0;
977
978error OutOfMemory;
996/// Allocator that fails after N allocations, useful for making sure out of
997/// memory conditions are handled correctly.
998pub const FailingAllocator = struct {
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 {
981 const addr = @ptrToInt(&some_mem[some_mem_index]);
982 const rem = @rem(addr, alignment);
983 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
984 const adjusted_index = some_mem_index + march_forward_bytes;
985 const end_index = adjusted_index + n;
986 if (end_index > some_mem.len) {
987 return error.OutOfMemory;
1019 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
1020 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
1021 if (self.index == self.fail_index) {
1022 return error.OutOfMemory;
1023 }
1024 self.index += 1;
1025 const result = %return self.internal_allocator.allocFn(self.internal_allocator, n, alignment);
1026 self.allocated_bytes += result.len;
1027 return result;
9881028 }
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 {
995 if (new_size <= old_mem.len) {
996 return old_mem[0..new_size];
997 } else {
998 const result = %return globalAlloc(self, new_size, alignment);
999 @memcpy(result.ptr, old_mem.ptr, old_mem.len);
1030 fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
1031 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
1032 if (new_size <= old_mem.len) {
1033 self.allocated_bytes -= old_mem.len - new_size;
1034 return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
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;
10001042 return result;
10011043 }
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 {
188188 if (elf.is_64) {
189189 if (sh_entry_size != 64) return error.InvalidFormat;
190190
191 for (elf.section_headers) |*section| {
192 section.name = %return in.readInt(elf.endian, u32);
193 section.sh_type = %return in.readInt(elf.endian, u32);
194 section.flags = %return in.readInt(elf.endian, u64);
195 section.addr = %return in.readInt(elf.endian, u64);
196 section.offset = %return in.readInt(elf.endian, u64);
197 section.size = %return in.readInt(elf.endian, u64);
198 section.link = %return in.readInt(elf.endian, u32);
199 section.info = %return in.readInt(elf.endian, u32);
200 section.addr_align = %return in.readInt(elf.endian, u64);
201 section.ent_size = %return in.readInt(elf.endian, u64);
191 for (elf.section_headers) |*elf_section| {
192 elf_section.name = %return in.readInt(elf.endian, u32);
193 elf_section.sh_type = %return in.readInt(elf.endian, u32);
194 elf_section.flags = %return in.readInt(elf.endian, u64);
195 elf_section.addr = %return in.readInt(elf.endian, u64);
196 elf_section.offset = %return in.readInt(elf.endian, u64);
197 elf_section.size = %return in.readInt(elf.endian, u64);
198 elf_section.link = %return in.readInt(elf.endian, u32);
199 elf_section.info = %return in.readInt(elf.endian, u32);
200 elf_section.addr_align = %return in.readInt(elf.endian, u64);
201 elf_section.ent_size = %return in.readInt(elf.endian, u64);
202202 }
203203 } else {
204204 if (sh_entry_size != 40) return error.InvalidFormat;
205205
206 for (elf.section_headers) |*section| {
206 for (elf.section_headers) |*elf_section| {
207207 // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ?
208 section.name = %return in.readInt(elf.endian, u32);
209 section.sh_type = %return in.readInt(elf.endian, u32);
210 section.flags = u64(%return in.readInt(elf.endian, u32));
211 section.addr = u64(%return in.readInt(elf.endian, u32));
212 section.offset = u64(%return in.readInt(elf.endian, u32));
213 section.size = u64(%return in.readInt(elf.endian, u32));
214 section.link = %return in.readInt(elf.endian, u32);
215 section.info = %return in.readInt(elf.endian, u32);
216 section.addr_align = u64(%return in.readInt(elf.endian, u32));
217 section.ent_size = u64(%return in.readInt(elf.endian, u32));
208 elf_section.name = %return in.readInt(elf.endian, u32);
209 elf_section.sh_type = %return in.readInt(elf.endian, u32);
210 elf_section.flags = u64(%return in.readInt(elf.endian, u32));
211 elf_section.addr = u64(%return in.readInt(elf.endian, u32));
212 elf_section.offset = u64(%return in.readInt(elf.endian, u32));
213 elf_section.size = u64(%return in.readInt(elf.endian, u32));
214 elf_section.link = %return in.readInt(elf.endian, u32);
215 elf_section.info = %return in.readInt(elf.endian, u32);
216 elf_section.addr_align = u64(%return in.readInt(elf.endian, u32));
217 elf_section.ent_size = u64(%return in.readInt(elf.endian, u32));
218218 }
219219 }
220220
221 for (elf.section_headers) |*section| {
222 if (section.sh_type != SHT_NOBITS) {
223 const file_end_offset = %return math.add(u64, section.offset, section.size);
221 for (elf.section_headers) |*elf_section| {
222 if (elf_section.sh_type != SHT_NOBITS) {
223 const file_end_offset = %return math.add(u64, elf_section.offset, elf_section.size);
224224 if (stream_end < file_end_offset) return error.InvalidFormat;
225225 }
226226 }
......@@ -243,29 +243,27 @@ pub const Elf = struct {
243243 var file_stream = io.FileInStream.init(elf.in_file);
244244 const in = &file_stream.stream;
245245
246 for (elf.section_headers) |*section| {
247 if (section.sh_type == SHT_NULL) continue;
246 section_loop: for (elf.section_headers) |*elf_section| {
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;
250250 %return elf.in_file.seekTo(name_offset);
251251
252252 for (name) |expected_c| {
253253 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;
255255 }
256256
257257 {
258258 const null_byte = %return in.readByte();
259 if (null_byte == 0) return section;
259 if (null_byte == 0) return elf_section;
260260 }
261
262 next_section:
263261 }
264262
265263 return null;
266264 }
267265
268 pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void {
269 %return elf.in_file.seekTo(section.offset);
266 pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) -> %void {
267 %return elf.in_file.seekTo(elf_section.offset);
270268 }
271269};
std/endian.zig+3-3
......@@ -2,15 +2,15 @@ const mem = @import("mem.zig");
22const builtin = @import("builtin");
33
44pub fn swapIfLe(comptime T: type, x: T) -> T {
5 swapIf(false, T, x)
5 return swapIf(false, T, x);
66}
77
88pub fn swapIfBe(comptime T: type, x: T) -> T {
9 swapIf(true, T, x)
9 return swapIf(true, T, x);
1010}
1111
1212pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {
13 if (builtin.endian == endian) swap(T, x) else x
13 return if (builtin.endian == endian) swap(T, x) else x;
1414}
1515
1616pub fn swap(comptime T: type, x: T) -> T {
std/fmt/errol/enum3.zig+2-2
......@@ -439,10 +439,10 @@ const Slab = struct {
439439};
440440
441441fn slab(str: []const u8, exp: i32) -> Slab {
442 Slab {
442 return Slab {
443443 .str = str,
444444 .exp = exp,
445 }
445 };
446446}
447447
448448pub 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
251251 %return output(context, float_decimal.digits[0..1]);
252252 %return output(context, ".");
253253 if (float_decimal.digits.len > 1) {
254 const num_digits = if (@typeOf(value) == f32) {
254 const num_digits = if (@typeOf(value) == f32)
255255 math.min(usize(9), float_decimal.digits.len)
256 } else {
257 float_decimal.digits.len
258 };
256 else
257 float_decimal.digits.len;
259258 %return output(context, float_decimal.digits[1 .. num_digits]);
260259 } else {
261260 %return output(context, "0");
......@@ -372,6 +371,10 @@ test "fmt.parseInt" {
372371 assert(%%parseInt(i32, "-10", 10) == -10);
373372 assert(%%parseInt(i32, "+10", 10) == 10);
374373 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);
375378}
376379
377380pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) -> %T {
......@@ -413,14 +416,16 @@ const BufPrintContext = struct {
413416 remaining: []u8,
414417};
415418
419error BufferTooSmall;
416420fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) -> %void {
421 if (context.remaining.len < bytes.len) return error.BufferTooSmall;
417422 mem.copy(u8, context.remaining, bytes);
418423 context.remaining = context.remaining[bytes.len..];
419424}
420425
421pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) -> []u8 {
426pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) -> %[]u8 {
422427 var context = BufPrintContext { .remaining = buf, };
423 %%format(&context, bufPrintWrite, fmt, args);
428 %return format(&context, bufPrintWrite, fmt, args);
424429 return buf[0..buf.len - context.remaining.len];
425430}
426431
......@@ -476,31 +481,31 @@ test "fmt.format" {
476481 {
477482 var buf1: [32]u8 = undefined;
478483 const value: ?i32 = 1234;
479 const result = bufPrint(buf1[0..], "nullable: {}\n", value);
484 const result = %%bufPrint(buf1[0..], "nullable: {}\n", value);
480485 assert(mem.eql(u8, result, "nullable: 1234\n"));
481486 }
482487 {
483488 var buf1: [32]u8 = undefined;
484489 const value: ?i32 = null;
485 const result = bufPrint(buf1[0..], "nullable: {}\n", value);
490 const result = %%bufPrint(buf1[0..], "nullable: {}\n", value);
486491 assert(mem.eql(u8, result, "nullable: null\n"));
487492 }
488493 {
489494 var buf1: [32]u8 = undefined;
490495 const value: %i32 = 1234;
491 const result = bufPrint(buf1[0..], "error union: {}\n", value);
496 const result = %%bufPrint(buf1[0..], "error union: {}\n", value);
492497 assert(mem.eql(u8, result, "error union: 1234\n"));
493498 }
494499 {
495500 var buf1: [32]u8 = undefined;
496501 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);
498503 assert(mem.eql(u8, result, "error union: error.InvalidChar\n"));
499504 }
500505 {
501506 var buf1: [32]u8 = undefined;
502507 const value: u3 = 0b101;
503 const result = bufPrint(buf1[0..], "u3: {}\n", value);
508 const result = %%bufPrint(buf1[0..], "u3: {}\n", value);
504509 assert(mem.eql(u8, result, "u3: 5\n"));
505510 }
506511
......@@ -510,28 +515,28 @@ test "fmt.format" {
510515 {
511516 var buf1: [32]u8 = undefined;
512517 const value: f32 = 12.34;
513 const result = bufPrint(buf1[0..], "f32: {}\n", value);
518 const result = %%bufPrint(buf1[0..], "f32: {}\n", value);
514519 assert(mem.eql(u8, result, "f32: 1.23400001e1\n"));
515520 }
516521 {
517522 var buf1: [32]u8 = undefined;
518523 const value: f64 = -12.34e10;
519 const result = bufPrint(buf1[0..], "f64: {}\n", value);
524 const result = %%bufPrint(buf1[0..], "f64: {}\n", value);
520525 assert(mem.eql(u8, result, "f64: -1.234e11\n"));
521526 }
522527 {
523528 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);
525530 assert(mem.eql(u8, result, "f64: NaN\n"));
526531 }
527532 {
528533 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);
530535 assert(mem.eql(u8, result, "f64: Infinity\n"));
531536 }
532537 {
533538 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);
535540 assert(mem.eql(u8, result, "f64: -Infinity\n"));
536541 }
537542 }
std/hash_map.zig+10-10
......@@ -12,7 +12,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
1212 comptime hash: fn(key: K)->u32,
1313 comptime eql: fn(a: K, b: K)->bool) -> type
1414{
15 struct {
15 return struct {
1616 entries: []Entry,
1717 size: usize,
1818 max_distance_from_start_index: usize,
......@@ -51,19 +51,19 @@ pub fn HashMap(comptime K: type, comptime V: type,
5151 return entry;
5252 }
5353 }
54 unreachable // no next item
54 unreachable; // no next item
5555 }
5656 };
5757
5858 pub fn init(allocator: &Allocator) -> Self {
59 Self {
59 return Self {
6060 .entries = []Entry{},
6161 .allocator = allocator,
6262 .size = 0,
6363 .max_distance_from_start_index = 0,
6464 // it doesn't actually matter what we set this to since we use wrapping integer arithmetic
6565 .modification_count = undefined,
66 }
66 };
6767 }
6868
6969 pub fn deinit(hm: &Self) {
......@@ -133,7 +133,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
133133 entry.distance_from_start_index -= 1;
134134 entry = next_entry;
135135 }
136 unreachable // shifting everything in the table
136 unreachable; // shifting everything in the table
137137 }}
138138 return null;
139139 }
......@@ -169,7 +169,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
169169 const start_index = hm.keyToIndex(key);
170170 var roll_over: usize = 0;
171171 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;}) {
173173 const index = (start_index + roll_over) % hm.entries.len;
174174 const entry = &hm.entries[index];
175175
......@@ -210,7 +210,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
210210 };
211211 return result;
212212 }
213 unreachable // put into a full map
213 unreachable; // put into a full map
214214 }
215215
216216 fn internalGet(hm: &Self, key: K) -> ?&Entry {
......@@ -228,7 +228,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
228228 fn keyToIndex(hm: &Self, key: K) -> usize {
229229 return usize(hash(key)) % hm.entries.len;
230230 }
231 }
231 };
232232}
233233
234234test "basicHashMapTest" {
......@@ -251,9 +251,9 @@ test "basicHashMapTest" {
251251}
252252
253253fn hash_i32(x: i32) -> u32 {
254 @bitCast(u32, x)
254 return @bitCast(u32, x);
255255}
256256
257257fn eql_i32(a: i32, b: i32) -> bool {
258 a == b
258 return a == b;
259259}
std/heap.zig+15-17
......@@ -10,30 +10,28 @@ const Allocator = mem.Allocator;
1010
1111error OutOfMemory;
1212
13pub var c_allocator = Allocator {
13pub const c_allocator = &c_allocator_state;
14var c_allocator_state = Allocator {
1415 .allocFn = cAlloc,
1516 .reallocFn = cRealloc,
1617 .freeFn = cFree,
1718};
1819
19fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {
20 if (c.malloc(usize(n))) |buf| {
20fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 {
21 return if (c.malloc(usize(n))) |buf|
2122 @ptrCast(&u8, buf)[0..n]
22 } else {
23 error.OutOfMemory
24 }
23 else
24 error.OutOfMemory;
2525}
2626
27fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
28 if (new_size <= old_mem.len) {
29 old_mem[0..new_size]
27fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
28 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
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];
3033 } else {
31 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
32 if (c.realloc(old_ptr, usize(new_size))) |buf| {
33 @ptrCast(&u8, buf)[0..new_size]
34 } else {
35 error.OutOfMemory
36 }
34 return error.OutOfMemory;
3735 }
3836}
3937
......@@ -106,7 +104,7 @@ pub const IncrementingAllocator = struct {
106104 return self.bytes.len - self.end_index;
107105 }
108106
109 fn alloc(allocator: &Allocator, n: usize, alignment: usize) -> %[]u8 {
107 fn alloc(allocator: &Allocator, n: usize, alignment: u29) -> %[]u8 {
110108 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
111109 const addr = @ptrToInt(&self.bytes[self.end_index]);
112110 const rem = @rem(addr, alignment);
......@@ -121,7 +119,7 @@ pub const IncrementingAllocator = struct {
121119 return result;
122120 }
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 {
125123 if (new_size <= old_mem.len) {
126124 return old_mem[0..new_size];
127125 } else {
std/index.zig+8-6
......@@ -1,7 +1,9 @@
11pub const ArrayList = @import("array_list.zig").ArrayList;
2pub const AlignedArrayList = @import("array_list.zig").AlignedArrayList;
23pub const BufMap = @import("buf_map.zig").BufMap;
34pub const BufSet = @import("buf_set.zig").BufSet;
45pub const Buffer = @import("buffer.zig").Buffer;
6pub const BufferOutStream = @import("buffer.zig").BufferOutStream;
57pub const HashMap = @import("hash_map.zig").HashMap;
68pub const LinkedList = @import("linked_list.zig").LinkedList;
79
......@@ -26,12 +28,12 @@ pub const sort = @import("sort.zig");
2628
2729test "std" {
2830 // run tests from these
29 _ = @import("array_list.zig").ArrayList;
30 _ = @import("buf_map.zig").BufMap;
31 _ = @import("buf_set.zig").BufSet;
32 _ = @import("buffer.zig").Buffer;
33 _ = @import("hash_map.zig").HashMap;
34 _ = @import("linked_list.zig").LinkedList;
31 _ = @import("array_list.zig");
32 _ = @import("buf_map.zig");
33 _ = @import("buf_set.zig");
34 _ = @import("buffer.zig");
35 _ = @import("hash_map.zig");
36 _ = @import("linked_list.zig");
3537
3638 _ = @import("base64.zig");
3739 _ = @import("build.zig");
std/io.zig+56-16
......@@ -50,35 +50,32 @@ error Unseekable;
5050error EndOfFile;
5151
5252pub fn getStdErr() -> %File {
53 const handle = if (is_windows) {
53 const handle = if (is_windows)
5454 %return os.windowsGetStdHandle(system.STD_ERROR_HANDLE)
55 } else if (is_posix) {
55 else if (is_posix)
5656 system.STDERR_FILENO
57 } else {
58 unreachable
59 };
57 else
58 unreachable;
6059 return File.openHandle(handle);
6160}
6261
6362pub fn getStdOut() -> %File {
64 const handle = if (is_windows) {
63 const handle = if (is_windows)
6564 %return os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE)
66 } else if (is_posix) {
65 else if (is_posix)
6766 system.STDOUT_FILENO
68 } else {
69 unreachable
70 };
67 else
68 unreachable;
7169 return File.openHandle(handle);
7270}
7371
7472pub fn getStdIn() -> %File {
75 const handle = if (is_windows) {
73 const handle = if (is_windows)
7674 %return os.windowsGetStdHandle(system.STD_INPUT_HANDLE)
77 } else if (is_posix) {
75 else if (is_posix)
7876 system.STDIN_FILENO
79 } else {
80 unreachable
81 };
77 else
78 unreachable;
8279 return File.openHandle(handle);
8380}
8481
......@@ -261,7 +258,7 @@ pub const File = struct {
261258 system.EBADF => error.BadFd,
262259 system.ENOMEM => error.SystemResources,
263260 else => os.unexpectedErrorPosix(err),
264 }
261 };
265262 }
266263
267264 return usize(stat.size);
......@@ -481,6 +478,14 @@ pub const OutStream = struct {
481478 const slice = (&byte)[0..1];
482479 return self.writeFn(self, slice);
483480 }
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 }
484489};
485490
486491/// `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)
493498 %return file.write(data);
494499}
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
496515pub const BufferedInStream = BufferedInStreamCustom(os.page_size);
497516
498517pub fn BufferedInStreamCustom(comptime buffer_size: usize) -> type {
......@@ -619,3 +638,24 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) -> type {
619638 }
620639 };
621640}
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;
55
66/// Generic doubly linked list.
77pub fn LinkedList(comptime T: type) -> type {
8 struct {
8 return struct {
99 const Self = this;
1010
1111 /// Node inside the linked list wrapping the actual data.
......@@ -15,11 +15,11 @@ pub fn LinkedList(comptime T: type) -> type {
1515 data: T,
1616
1717 pub fn init(data: &const T) -> Node {
18 Node {
18 return Node {
1919 .prev = null,
2020 .next = null,
2121 .data = *data,
22 }
22 };
2323 }
2424 };
2525
......@@ -32,11 +32,11 @@ pub fn LinkedList(comptime T: type) -> type {
3232 /// Returns:
3333 /// An empty linked list.
3434 pub fn init() -> Self {
35 Self {
35 return Self {
3636 .first = null,
3737 .last = null,
3838 .len = 0,
39 }
39 };
4040 }
4141
4242 /// Insert a new node after an existing one.
......@@ -166,7 +166,7 @@ pub fn LinkedList(comptime T: type) -> type {
166166 /// Returns:
167167 /// A pointer to the new node.
168168 pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node {
169 allocator.create(Node)
169 return allocator.create(Node);
170170 }
171171
172172 /// Deallocate a node.
......@@ -191,7 +191,7 @@ pub fn LinkedList(comptime T: type) -> type {
191191 *node = Node.init(data);
192192 return node;
193193 }
194 }
194 };
195195}
196196
197197test "basic linked list test" {
std/math/acos.zig+8-8
......@@ -7,11 +7,11 @@ const assert = @import("../debug.zig").assert;
77
88pub fn acos(x: var) -> @typeOf(x) {
99 const T = @typeOf(x);
10 switch (T) {
11 f32 => @inlineCall(acos32, x),
12 f64 => @inlineCall(acos64, x),
10 return switch (T) {
11 f32 => acos32(x),
12 f64 => acos64(x),
1313 else => @compileError("acos not implemented for " ++ @typeName(T)),
14 }
14 };
1515}
1616
1717fn r32(z: f32) -> f32 {
......@@ -22,7 +22,7 @@ fn r32(z: f32) -> f32 {
2222
2323 const p = z * (pS0 + z * (pS1 + z * pS2));
2424 const q = 1.0 + z * qS1;
25 p / q
25 return p / q;
2626}
2727
2828fn acos32(x: f32) -> f32 {
......@@ -69,7 +69,7 @@ fn acos32(x: f32) -> f32 {
6969 const df = @bitCast(f32, jx & 0xFFFFF000);
7070 const c = (z - df * df) / (s + df);
7171 const w = r32(z) * s + c;
72 2 * (df + w)
72 return 2 * (df + w);
7373}
7474
7575fn r64(z: f64) -> f64 {
......@@ -86,7 +86,7 @@ fn r64(z: f64) -> f64 {
8686
8787 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
8888 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
89 p / q
89 return p / q;
9090}
9191
9292fn acos64(x: f64) -> f64 {
......@@ -138,7 +138,7 @@ fn acos64(x: f64) -> f64 {
138138 const df = @bitCast(f64, jx & 0xFFFFFFFF00000000);
139139 const c = (z - df * df) / (s + df);
140140 const w = r64(z) * s + c;
141 2 * (df + w)
141 return 2 * (df + w);
142142}
143143
144144test "math.acos" {
std/math/acosh.zig+10-10
......@@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
99
1010pub fn acosh(x: var) -> @typeOf(x) {
1111 const T = @typeOf(x);
12 switch (T) {
13 f32 => @inlineCall(acosh32, x),
14 f64 => @inlineCall(acosh64, x),
12 return switch (T) {
13 f32 => acosh32(x),
14 f64 => acosh64(x),
1515 else => @compileError("acosh not implemented for " ++ @typeName(T)),
16 }
16 };
1717}
1818
1919// acosh(x) = log(x + sqrt(x * x - 1))
......@@ -23,15 +23,15 @@ fn acosh32(x: f32) -> f32 {
2323
2424 // |x| < 2, invalid if x < 1 or nan
2525 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)));
2727 }
2828 // |x| < 0x1p12
2929 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)));
3131 }
3232 // |x| >= 0x1p12
3333 else {
34 math.ln(x) + 0.693147180559945309417232121458176568
34 return math.ln(x) + 0.693147180559945309417232121458176568;
3535 }
3636}
3737
......@@ -41,15 +41,15 @@ fn acosh64(x: f64) -> f64 {
4141
4242 // |x| < 2, invalid if x < 1 or nan
4343 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)));
4545 }
4646 // |x| < 0x1p26
4747 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)));
4949 }
5050 // |x| >= 0x1p26 or nan
5151 else {
52 math.ln(x) + 0.693147180559945309417232121458176568
52 return math.ln(x) + 0.693147180559945309417232121458176568;
5353 }
5454}
5555
std/math/asin.zig+11-11
......@@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
88
99pub fn asin(x: var) -> @typeOf(x) {
1010 const T = @typeOf(x);
11 switch (T) {
12 f32 => @inlineCall(asin32, x),
13 f64 => @inlineCall(asin64, x),
11 return switch (T) {
12 f32 => asin32(x),
13 f64 => asin64(x),
1414 else => @compileError("asin not implemented for " ++ @typeName(T)),
15 }
15 };
1616}
1717
1818fn r32(z: f32) -> f32 {
......@@ -23,7 +23,7 @@ fn r32(z: f32) -> f32 {
2323
2424 const p = z * (pS0 + z * (pS1 + z * pS2));
2525 const q = 1.0 + z * qS1;
26 p / q
26 return p / q;
2727}
2828
2929fn asin32(x: f32) -> f32 {
......@@ -58,9 +58,9 @@ fn asin32(x: f32) -> f32 {
5858 const fx = pio2 - 2 * (s + s * r32(z));
5959
6060 if (hx >> 31 != 0) {
61 -fx
61 return -fx;
6262 } else {
63 fx
63 return fx;
6464 }
6565}
6666
......@@ -78,7 +78,7 @@ fn r64(z: f64) -> f64 {
7878
7979 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
8080 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
81 p / q
81 return p / q;
8282}
8383
8484fn asin64(x: f64) -> f64 {
......@@ -119,7 +119,7 @@ fn asin64(x: f64) -> f64 {
119119
120120 // |x| > 0.975
121121 if (ix >= 0x3FEF3333) {
122 fx = pio2_hi - 2 * (s + s * r)
122 fx = pio2_hi - 2 * (s + s * r);
123123 } else {
124124 const jx = @bitCast(u64, s);
125125 const df = @bitCast(f64, jx & 0xFFFFFFFF00000000);
......@@ -128,9 +128,9 @@ fn asin64(x: f64) -> f64 {
128128 }
129129
130130 if (hx >> 31 != 0) {
131 -fx
131 return -fx;
132132 } else {
133 fx
133 return fx;
134134 }
135135}
136136
std/math/asinh.zig+6-6
......@@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
99
1010pub fn asinh(x: var) -> @typeOf(x) {
1111 const T = @typeOf(x);
12 switch (T) {
13 f32 => @inlineCall(asinh32, x),
14 f64 => @inlineCall(asinh64, x),
12 return switch (T) {
13 f32 => asinh32(x),
14 f64 => asinh64(x),
1515 else => @compileError("asinh not implemented for " ++ @typeName(T)),
16 }
16 };
1717}
1818
1919// 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 {
4646 math.forceEval(x + 0x1.0p120);
4747 }
4848
49 if (s != 0) -rx else rx
49 return if (s != 0) -rx else rx;
5050}
5151
5252fn asinh64(x: f64) -> f64 {
......@@ -77,7 +77,7 @@ fn asinh64(x: f64) -> f64 {
7777 math.forceEval(x + 0x1.0p120);
7878 }
7979
80 if (s != 0) -rx else rx
80 return if (s != 0) -rx else rx;
8181}
8282
8383test "math.asinh" {
std/math/atan.zig+13-13
......@@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
88
99pub fn atan(x: var) -> @typeOf(x) {
1010 const T = @typeOf(x);
11 switch (T) {
12 f32 => @inlineCall(atan32, x),
13 f64 => @inlineCall(atan64, x),
11 return switch (T) {
12 f32 => atan32(x),
13 f64 => atan64(x),
1414 else => @compileError("atan not implemented for " ++ @typeName(T)),
15 }
15 };
1616}
1717
1818fn atan32(x_: f32) -> f32 {
......@@ -99,11 +99,11 @@ fn atan32(x_: f32) -> f32 {
9999 const s1 = z * (aT[0] + w * (aT[2] + w * aT[4]));
100100 const s2 = w * (aT[1] + w * aT[3]);
101101
102 if (id == null) {
103 x - x * (s1 + s2)
102 if (id) |id_value| {
103 const zz = atanhi[id_value] - ((x * (s1 + s2) - atanlo[id_value]) - x);
104 return if (sign != 0) -zz else zz;
104105 } else {
105 const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x);
106 if (sign != 0) -zz else zz
106 return x - x * (s1 + s2);
107107 }
108108}
109109
......@@ -198,16 +198,16 @@ fn atan64(x_: f64) -> f64 {
198198 const s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10])))));
199199 const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9]))));
200200
201 if (id == null) {
202 x - x * (s1 + s2)
201 if (id) |id_value| {
202 const zz = atanhi[id_value] - ((x * (s1 + s2) - atanlo[id_value]) - x);
203 return if (sign != 0) -zz else zz;
203204 } else {
204 const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x);
205 if (sign != 0) -zz else zz
205 return x - x * (s1 + s2);
206206 }
207207}
208208
209209test "math.atan" {
210 assert(atan(f32(0.2)) == atan32(0.2));
210 assert(@bitCast(u32, atan(f32(0.2))) == @bitCast(u32, atan32(0.2)));
211211 assert(atan(f64(0.2)) == atan64(0.2));
212212}
213213
std/math/atan2.zig+10-10
......@@ -22,11 +22,11 @@ const math = @import("index.zig");
2222const assert = @import("../debug.zig").assert;
2323
2424fn atan2(comptime T: type, x: T, y: T) -> T {
25 switch (T) {
26 f32 => @inlineCall(atan2_32, x, y),
27 f64 => @inlineCall(atan2_64, x, y),
25 return switch (T) {
26 f32 => atan2_32(x, y),
27 f64 => atan2_64(x, y),
2828 else => @compileError("atan2 not implemented for " ++ @typeName(T)),
29 }
29 };
3030}
3131
3232fn atan2_32(y: f32, x: f32) -> f32 {
......@@ -97,11 +97,11 @@ fn atan2_32(y: f32, x: f32) -> f32 {
9797 }
9898
9999 // z = atan(|y / x|) with correct underflow
100 var z = {
100 var z = z: {
101101 if ((m & 2) != 0 and iy + (26 << 23) < ix) {
102 0.0
102 break :z 0.0;
103103 } else {
104 math.atan(math.fabs(y / x))
104 break :z math.atan(math.fabs(y / x));
105105 }
106106 };
107107
......@@ -187,11 +187,11 @@ fn atan2_64(y: f64, x: f64) -> f64 {
187187 }
188188
189189 // z = atan(|y / x|) with correct underflow
190 var z = {
190 var z = z: {
191191 if ((m & 2) != 0 and iy +% (64 << 20) < ix) {
192 0.0
192 break :z 0.0;
193193 } else {
194 math.atan(math.fabs(y / x))
194 break :z math.atan(math.fabs(y / x));
195195 }
196196 };
197197
std/math/atanh.zig+7-7
......@@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
99
1010pub fn atanh(x: var) -> @typeOf(x) {
1111 const T = @typeOf(x);
12 switch (T) {
13 f32 => @inlineCall(atanh_32, x),
14 f64 => @inlineCall(atanh_64, x),
12 return switch (T) {
13 f32 => atanh_32(x),
14 f64 => atanh_64(x),
1515 else => @compileError("atanh not implemented for " ++ @typeName(T)),
16 }
16 };
1717}
1818
1919// 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 {
3232 if (u < 0x3F800000 - (32 << 23)) {
3333 // underflow
3434 if (u < (1 << 23)) {
35 math.forceEval(y * y)
35 math.forceEval(y * y);
3636 }
3737 }
3838 // |x| < 0.5
......@@ -43,7 +43,7 @@ fn atanh_32(x: f32) -> f32 {
4343 y = 0.5 * math.log1p(2 * (y / (1 - y)));
4444 }
4545
46 if (s != 0) -y else y
46 return if (s != 0) -y else y;
4747}
4848
4949fn atanh_64(x: f64) -> f64 {
......@@ -72,7 +72,7 @@ fn atanh_64(x: f64) -> f64 {
7272 y = 0.5 * math.log1p(2 * (y / (1 - y)));
7373 }
7474
75 if (s != 0) -y else y
75 return if (s != 0) -y else y;
7676}
7777
7878test "math.atanh" {
std/math/cbrt.zig+6-6
......@@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
99
1010pub fn cbrt(x: var) -> @typeOf(x) {
1111 const T = @typeOf(x);
12 switch (T) {
13 f32 => @inlineCall(cbrt32, x),
14 f64 => @inlineCall(cbrt64, x),
12 return switch (T) {
13 f32 => cbrt32(x),
14 f64 => cbrt64(x),
1515 else => @compileError("cbrt not implemented for " ++ @typeName(T)),
16 }
16 };
1717}
1818
1919fn cbrt32(x: f32) -> f32 {
......@@ -53,7 +53,7 @@ fn cbrt32(x: f32) -> f32 {
5353 r = t * t * t;
5454 t = t * (f64(x) + x + r) / (x + r + r);
5555
56 f32(t)
56 return f32(t);
5757}
5858
5959fn cbrt64(x: f64) -> f64 {
......@@ -109,7 +109,7 @@ fn cbrt64(x: f64) -> f64 {
109109 var w = t + t;
110110 q = (q - t) / (w + q);
111111
112 t + t * q
112 return t + t * q;
113113}
114114
115115test "math.cbrt" {
std/math/ceil.zig+10-10
......@@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert;
1010
1111pub fn ceil(x: var) -> @typeOf(x) {
1212 const T = @typeOf(x);
13 switch (T) {
14 f32 => @inlineCall(ceil32, x),
15 f64 => @inlineCall(ceil64, x),
13 return switch (T) {
14 f32 => ceil32(x),
15 f64 => ceil64(x),
1616 else => @compileError("ceil not implemented for " ++ @typeName(T)),
17 }
17 };
1818}
1919
2020fn ceil32(x: f32) -> f32 {
......@@ -39,13 +39,13 @@ fn ceil32(x: f32) -> f32 {
3939 u += m;
4040 }
4141 u &= ~m;
42 @bitCast(f32, u)
42 return @bitCast(f32, u);
4343 } else {
4444 math.forceEval(x + 0x1.0p120);
4545 if (u >> 31 != 0) {
4646 return -0.0;
4747 } else {
48 1.0
48 return 1.0;
4949 }
5050 }
5151}
......@@ -70,14 +70,14 @@ fn ceil64(x: f64) -> f64 {
7070 if (e <= 0x3FF-1) {
7171 math.forceEval(y);
7272 if (u >> 63 != 0) {
73 return -0.0; // Compiler requires return.
73 return -0.0;
7474 } else {
75 1.0
75 return 1.0;
7676 }
7777 } else if (y < 0) {
78 x + y + 1
78 return x + y + 1;
7979 } else {
80 x + y
80 return x + y;
8181 }
8282}
8383
std/math/copysign.zig+6-6
......@@ -2,11 +2,11 @@ const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
44pub fn copysign(comptime T: type, x: T, y: T) -> T {
5 switch (T) {
6 f32 => @inlineCall(copysign32, x, y),
7 f64 => @inlineCall(copysign64, x, y),
5 return switch (T) {
6 f32 => copysign32(x, y),
7 f64 => copysign64(x, y),
88 else => @compileError("copysign not implemented for " ++ @typeName(T)),
9 }
9 };
1010}
1111
1212fn copysign32(x: f32, y: f32) -> f32 {
......@@ -15,7 +15,7 @@ fn copysign32(x: f32, y: f32) -> f32 {
1515
1616 const h1 = ux & (@maxValue(u32) / 2);
1717 const h2 = uy & (u32(1) << 31);
18 @bitCast(f32, h1 | h2)
18 return @bitCast(f32, h1 | h2);
1919}
2020
2121fn copysign64(x: f64, y: f64) -> f64 {
......@@ -24,7 +24,7 @@ fn copysign64(x: f64, y: f64) -> f64 {
2424
2525 const h1 = ux & (@maxValue(u64) / 2);
2626 const h2 = uy & (u64(1) << 63);
27 @bitCast(f64, h1 | h2)
27 return @bitCast(f64, h1 | h2);
2828}
2929
3030test "math.copysign" {
std/math/cos.zig+14-14
......@@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
99
1010pub fn cos(x: var) -> @typeOf(x) {
1111 const T = @typeOf(x);
12 switch (T) {
13 f32 => @inlineCall(cos32, x),
14 f64 => @inlineCall(cos64, x),
12 return switch (T) {
13 f32 => cos32(x),
14 f64 => cos64(x),
1515 else => @compileError("cos not implemented for " ++ @typeName(T)),
16 }
16 };
1717}
1818
1919// sin polynomial coefficients
......@@ -73,18 +73,18 @@ fn cos32(x_: f32) -> f32 {
7373 const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
7474 const w = z * z;
7575
76 const r = {
76 const r = r: {
7777 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)))));
7979 } 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)))));
8181 }
8282 };
8383
8484 if (sign) {
85 -r
85 return -r;
8686 } else {
87 r
87 return r;
8888 }
8989}
9090
......@@ -124,18 +124,18 @@ fn cos64(x_: f64) -> f64 {
124124 const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
125125 const w = z * z;
126126
127 const r = {
127 const r = r: {
128128 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)))));
130130 } 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)))));
132132 }
133133 };
134134
135135 if (sign) {
136 -r
136 return -r;
137137 } else {
138 r
138 return r;
139139 }
140140}
141141
std/math/cosh.zig+6-6
......@@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert;
1111
1212pub fn cosh(x: var) -> @typeOf(x) {
1313 const T = @typeOf(x);
14 switch (T) {
15 f32 => @inlineCall(cosh32, x),
16 f64 => @inlineCall(cosh64, x),
14 return switch (T) {
15 f32 => cosh32(x),
16 f64 => cosh64(x),
1717 else => @compileError("cosh not implemented for " ++ @typeName(T)),
18 }
18 };
1919}
2020
2121// cosh(x) = (exp(x) + 1 / exp(x)) / 2
......@@ -43,7 +43,7 @@ fn cosh32(x: f32) -> f32 {
4343 }
4444
4545 // |x| > log(FLT_MAX) or nan
46 expo2(ax)
46 return expo2(ax);
4747}
4848
4949fn cosh64(x: f64) -> f64 {
......@@ -76,7 +76,7 @@ fn cosh64(x: f64) -> f64 {
7676 }
7777
7878 // |x| > log(CBL_MAX) or nan
79 expo2(ax)
79 return expo2(ax);
8080}
8181
8282test "math.cosh" {
std/math/exp.zig+8-8
......@@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
88
99pub fn exp(x: var) -> @typeOf(x) {
1010 const T = @typeOf(x);
11 switch (T) {
12 f32 => @inlineCall(exp32, x),
13 f64 => @inlineCall(exp64, x),
11 return switch (T) {
12 f32 => exp32(x),
13 f64 => exp64(x),
1414 else => @compileError("exp not implemented for " ++ @typeName(T)),
15 }
15 };
1616}
1717
1818fn exp32(x_: f32) -> f32 {
......@@ -86,9 +86,9 @@ fn exp32(x_: f32) -> f32 {
8686 const y = 1 + (x * c / (2 - c) - lo + hi);
8787
8888 if (k == 0) {
89 y
89 return y;
9090 } else {
91 math.scalbn(y, k)
91 return math.scalbn(y, k);
9292 }
9393}
9494
......@@ -172,9 +172,9 @@ fn exp64(x_: f64) -> f64 {
172172 const y = 1 + (x * c / (2 - c) - lo + hi);
173173
174174 if (k == 0) {
175 y
175 return y;
176176 } else {
177 math.scalbn(y, k)
177 return math.scalbn(y, k);
178178 }
179179}
180180
std/math/exp2.zig+6-6
......@@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
88
99pub fn exp2(x: var) -> @typeOf(x) {
1010 const T = @typeOf(x);
11 switch (T) {
12 f32 => @inlineCall(exp2_32, x),
13 f64 => @inlineCall(exp2_64, x),
11 return switch (T) {
12 f32 => exp2_32(x),
13 f64 => exp2_64(x),
1414 else => @compileError("exp2 not implemented for " ++ @typeName(T)),
15 }
15 };
1616}
1717
1818const exp2ft = []const f64 {
......@@ -88,7 +88,7 @@ fn exp2_32(x: f32) -> f32 {
8888 var r: f64 = exp2ft[i0];
8989 const t: f64 = r * z;
9090 r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4);
91 f32(r * uk)
91 return f32(r * uk);
9292}
9393
9494const exp2dt = []f64 {
......@@ -414,7 +414,7 @@ fn exp2_64(x: f64) -> f64 {
414414 z -= exp2dt[2 * i0 + 1];
415415 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);
418418}
419419
420420test "math.exp2" {
std/math/expm1.zig+4-4
......@@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
99
1010pub fn expm1(x: var) -> @typeOf(x) {
1111 const T = @typeOf(x);
12 switch (T) {
13 f32 => @inlineCall(expm1_32, x),
14 f64 => @inlineCall(expm1_64, x),
12 return switch (T) {
13 f32 => expm1_32(x),
14 f64 => expm1_64(x),
1515 else => @compileError("exp1m not implemented for " ++ @typeName(T)),
16 }
16 };
1717}
1818
1919fn expm1_32(x_: f32) -> f32 {
std/math/expo2.zig+4-4
......@@ -2,11 +2,11 @@ const math = @import("index.zig");
22
33pub fn expo2(x: var) -> @typeOf(x) {
44 const T = @typeOf(x);
5 switch (T) {
5 return switch (T) {
66 f32 => expo2f(x),
77 f64 => expo2d(x),
88 else => @compileError("expo2 not implemented for " ++ @typeName(T)),
9 }
9 };
1010}
1111
1212fn expo2f(x: f32) -> f32 {
......@@ -15,7 +15,7 @@ fn expo2f(x: f32) -> f32 {
1515
1616 const u = (0x7F + k / 2) << 23;
1717 const scale = @bitCast(f32, u);
18 math.exp(x - kln2) * scale * scale
18 return math.exp(x - kln2) * scale * scale;
1919}
2020
2121fn expo2d(x: f64) -> f64 {
......@@ -24,5 +24,5 @@ fn expo2d(x: f64) -> f64 {
2424
2525 const u = (0x3FF + k / 2) << 20;
2626 const scale = @bitCast(f64, u64(u) << 32);
27 math.exp(x - kln2) * scale * scale
27 return math.exp(x - kln2) * scale * scale;
2828}
std/math/fabs.zig+6-6
......@@ -8,23 +8,23 @@ const assert = @import("../debug.zig").assert;
88
99pub fn fabs(x: var) -> @typeOf(x) {
1010 const T = @typeOf(x);
11 switch (T) {
12 f32 => @inlineCall(fabs32, x),
13 f64 => @inlineCall(fabs64, x),
11 return switch (T) {
12 f32 => fabs32(x),
13 f64 => fabs64(x),
1414 else => @compileError("fabs not implemented for " ++ @typeName(T)),
15 }
15 };
1616}
1717
1818fn fabs32(x: f32) -> f32 {
1919 var u = @bitCast(u32, x);
2020 u &= 0x7FFFFFFF;
21 @bitCast(f32, u)
21 return @bitCast(f32, u);
2222}
2323
2424fn fabs64(x: f64) -> f64 {
2525 var u = @bitCast(u64, x);
2626 u &= @maxValue(u64) >> 1;
27 @bitCast(f64, u)
27 return @bitCast(f64, u);
2828}
2929
3030test "math.fabs" {
std/math/floor.zig+11-11
......@@ -10,11 +10,11 @@ const math = @import("index.zig");
1010
1111pub fn floor(x: var) -> @typeOf(x) {
1212 const T = @typeOf(x);
13 switch (T) {
14 f32 => @inlineCall(floor32, x),
15 f64 => @inlineCall(floor64, x),
13 return switch (T) {
14 f32 => floor32(x),
15 f64 => floor64(x),
1616 else => @compileError("floor not implemented for " ++ @typeName(T)),
17 }
17 };
1818}
1919
2020fn floor32(x: f32) -> f32 {
......@@ -40,13 +40,13 @@ fn floor32(x: f32) -> f32 {
4040 if (u >> 31 != 0) {
4141 u += m;
4242 }
43 @bitCast(f32, u & ~m)
43 return @bitCast(f32, u & ~m);
4444 } else {
4545 math.forceEval(x + 0x1.0p120);
4646 if (u >> 31 == 0) {
47 return 0.0; // Compiler requires return
47 return 0.0;
4848 } else {
49 -1.0
49 return -1.0;
5050 }
5151 }
5252}
......@@ -71,14 +71,14 @@ fn floor64(x: f64) -> f64 {
7171 if (e <= 0x3FF-1) {
7272 math.forceEval(y);
7373 if (u >> 63 != 0) {
74 return -1.0; // Compiler requires return.
74 return -1.0;
7575 } else {
76 0.0
76 return 0.0;
7777 }
7878 } else if (y > 0) {
79 x + y - 1
79 return x + y - 1;
8080 } else {
81 x + y
81 return x + y;
8282 }
8383}
8484
std/math/fma.zig+12-12
......@@ -2,11 +2,11 @@ const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
44pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {
5 switch (T) {
6 f32 => @inlineCall(fma32, x, y, z),
7 f64 => @inlineCall(fma64, x, y ,z),
5 return switch (T) {
6 f32 => fma32(x, y, z),
7 f64 => fma64(x, y ,z),
88 else => @compileError("fma not implemented for " ++ @typeName(T)),
9 }
9 };
1010}
1111
1212fn fma32(x: f32, y: f32, z: f32) -> f32 {
......@@ -16,10 +16,10 @@ fn fma32(x: f32, y: f32, z: f32) -> f32 {
1616 const e = (u >> 52) & 0x7FF;
1717
1818 if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or xy_z - xy == z) {
19 f32(xy_z)
19 return f32(xy_z);
2020 } else {
2121 // TODO: Handle inexact case with double-rounding
22 f32(xy_z)
22 return f32(xy_z);
2323 }
2424}
2525
......@@ -64,9 +64,9 @@ fn fma64(x: f64, y: f64, z: f64) -> f64 {
6464
6565 const adj = add_adjusted(r.lo, xy.lo);
6666 if (spread + math.ilogb(r.hi) > -1023) {
67 math.scalbn(r.hi + adj, spread)
67 return math.scalbn(r.hi + adj, spread);
6868 } else {
69 add_and_denorm(r.hi, adj, spread)
69 return add_and_denorm(r.hi, adj, spread);
7070 }
7171}
7272
......@@ -77,7 +77,7 @@ fn dd_add(a: f64, b: f64) -> dd {
7777 ret.hi = a + b;
7878 const s = ret.hi - a;
7979 ret.lo = (a - (ret.hi - s)) + (b - s);
80 ret
80 return ret;
8181}
8282
8383fn dd_mul(a: f64, b: f64) -> dd {
......@@ -99,7 +99,7 @@ fn dd_mul(a: f64, b: f64) -> dd {
9999
100100 ret.hi = p + q;
101101 ret.lo = p - ret.hi + q + la * lb;
102 ret
102 return ret;
103103}
104104
105105fn add_adjusted(a: f64, b: f64) -> f64 {
......@@ -113,7 +113,7 @@ fn add_adjusted(a: f64, b: f64) -> f64 {
113113 sum.hi = @bitCast(f64, uhii);
114114 }
115115 }
116 sum.hi
116 return sum.hi;
117117}
118118
119119fn 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 {
127127 sum.hi = @bitCast(f64, uhii);
128128 }
129129 }
130 math.scalbn(sum.hi, scale)
130 return math.scalbn(sum.hi, scale);
131131}
132132
133133test "math.fma" {
std/math/frexp.zig+8-8
......@@ -8,21 +8,21 @@ const math = @import("index.zig");
88const assert = @import("../debug.zig").assert;
99
1010fn frexp_result(comptime T: type) -> type {
11 struct {
11 return struct {
1212 significand: T,
1313 exponent: i32,
14 }
14 };
1515}
1616pub const frexp32_result = frexp_result(f32);
1717pub const frexp64_result = frexp_result(f64);
1818
1919pub fn frexp(x: var) -> frexp_result(@typeOf(x)) {
2020 const T = @typeOf(x);
21 switch (T) {
22 f32 => @inlineCall(frexp32, x),
23 f64 => @inlineCall(frexp64, x),
21 return switch (T) {
22 f32 => frexp32(x),
23 f64 => frexp64(x),
2424 else => @compileError("frexp not implemented for " ++ @typeName(T)),
25 }
25 };
2626}
2727
2828fn frexp32(x: f32) -> frexp32_result {
......@@ -59,7 +59,7 @@ fn frexp32(x: f32) -> frexp32_result {
5959 y &= 0x807FFFFF;
6060 y |= 0x3F000000;
6161 result.significand = @bitCast(f32, y);
62 result
62 return result;
6363}
6464
6565fn frexp64(x: f64) -> frexp64_result {
......@@ -96,7 +96,7 @@ fn frexp64(x: f64) -> frexp64_result {
9696 y &= 0x800FFFFFFFFFFFFF;
9797 y |= 0x3FE0000000000000;
9898 result.significand = @bitCast(f64, y);
99 result
99 return result;
100100}
101101
102102test "math.frexp" {
std/math/hypot.zig+6-6
......@@ -9,11 +9,11 @@ const math = @import("index.zig");
99const assert = @import("../debug.zig").assert;
1010
1111pub fn hypot(comptime T: type, x: T, y: T) -> T {
12 switch (T) {
13 f32 => @inlineCall(hypot32, x, y),
14 f64 => @inlineCall(hypot64, x, y),
12 return switch (T) {
13 f32 => hypot32(x, y),
14 f64 => hypot64(x, y),
1515 else => @compileError("hypot not implemented for " ++ @typeName(T)),
16 }
16 };
1717}
1818
1919fn hypot32(x: f32, y: f32) -> f32 {
......@@ -48,7 +48,7 @@ fn hypot32(x: f32, y: f32) -> f32 {
4848 yy *= 0x1.0p-90;
4949 }
5050
51 z * math.sqrt(f32(f64(x) * x + f64(y) * y))
51 return z * math.sqrt(f32(f64(x) * x + f64(y) * y));
5252}
5353
5454fn sq(hi: &f64, lo: &f64, x: f64) {
......@@ -109,7 +109,7 @@ fn hypot64(x: f64, y: f64) -> f64 {
109109 sq(&hx, &lx, x);
110110 sq(&hy, &ly, y);
111111
112 z * math.sqrt(ly + lx + hy + hx)
112 return z * math.sqrt(ly + lx + hy + hx);
113113}
114114
115115test "math.hypot" {
std/math/ilogb.zig+6-6
......@@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
99
1010pub fn ilogb(x: var) -> i32 {
1111 const T = @typeOf(x);
12 switch (T) {
13 f32 => @inlineCall(ilogb32, x),
14 f64 => @inlineCall(ilogb64, x),
12 return switch (T) {
13 f32 => ilogb32(x),
14 f64 => ilogb64(x),
1515 else => @compileError("ilogb not implemented for " ++ @typeName(T)),
16 }
16 };
1717}
1818
1919// NOTE: Should these be exposed publically?
......@@ -53,7 +53,7 @@ fn ilogb32(x: f32) -> i32 {
5353 }
5454 }
5555
56 e - 0x7F
56 return e - 0x7F;
5757}
5858
5959fn ilogb64(x: f64) -> i32 {
......@@ -88,7 +88,7 @@ fn ilogb64(x: f64) -> i32 {
8888 }
8989 }
9090
91 e - 0x3FF
91 return e - 0x3FF;
9292}
9393
9494test "math.ilogb" {
std/math/index.zig+33-14
......@@ -36,7 +36,7 @@ pub const inf = @import("inf.zig").inf;
3636
3737pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) -> bool {
3838 assert(@typeId(T) == TypeId.Float);
39 fabs(x - y) < epsilon
39 return fabs(x - y) < epsilon;
4040}
4141
4242// TODO: Hide the following in an internal module.
......@@ -174,14 +174,8 @@ test "math" {
174174}
175175
176176
177pub const Cmp = enum {
178 Less,
179 Equal,
180 Greater,
181};
182
183177pub fn min(x: var, y: var) -> @typeOf(x + y) {
184 if (x < y) x else y
178 return if (x < y) x else y;
185179}
186180
187181test "math.min" {
......@@ -189,7 +183,7 @@ test "math.min" {
189183}
190184
191185pub fn max(x: var, y: var) -> @typeOf(x + y) {
192 if (x > y) x else y
186 return if (x > y) x else y;
193187}
194188
195189test "math.max" {
......@@ -199,19 +193,19 @@ test "math.max" {
199193error Overflow;
200194pub fn mul(comptime T: type, a: T, b: T) -> %T {
201195 var answer: T = undefined;
202 if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer
196 return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
203197}
204198
205199error Overflow;
206200pub fn add(comptime T: type, a: T, b: T) -> %T {
207201 var answer: T = undefined;
208 if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer
202 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
209203}
210204
211205error Overflow;
212206pub fn sub(comptime T: type, a: T, b: T) -> %T {
213207 var answer: T = undefined;
214 if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer
208 return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
215209}
216210
217211pub fn negate(x: var) -> %@typeOf(x) {
......@@ -221,7 +215,7 @@ pub fn negate(x: var) -> %@typeOf(x) {
221215error Overflow;
222216pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) -> %T {
223217 var answer: T = undefined;
224 if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer
218 return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
225219}
226220
227221/// Shifts left. Overflowed bits are truncated.
......@@ -273,7 +267,7 @@ test "math.shr" {
273267}
274268
275269pub fn Log2Int(comptime T: type) -> type {
276 @IntType(false, log2(T.bit_count))
270 return @IntType(false, log2(T.bit_count));
277271}
278272
279273test "math overflow functions" {
......@@ -522,3 +516,28 @@ pub fn cast(comptime T: type, x: var) -> %T {
522516 return T(x);
523517 }
524518}
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");
22const assert = @import("../debug.zig").assert;
33
44pub fn inf(comptime T: type) -> T {
5 switch (T) {
5 return switch (T) {
66 f32 => @bitCast(f32, math.inf_u32),
77 f64 => @bitCast(f64, math.inf_u64),
88 else => @compileError("inf not implemented for " ++ @typeName(T)),
9 }
9 };
1010}
std/math/isfinite.zig+2-2
......@@ -6,11 +6,11 @@ pub fn isFinite(x: var) -> bool {
66 switch (T) {
77 f32 => {
88 const bits = @bitCast(u32, x);
9 bits & 0x7FFFFFFF < 0x7F800000
9 return bits & 0x7FFFFFFF < 0x7F800000;
1010 },
1111 f64 => {
1212 const bits = @bitCast(u64, x);
13 bits & (@maxValue(u64) >> 1) < (0x7FF << 52)
13 return bits & (@maxValue(u64) >> 1) < (0x7FF << 52);
1414 },
1515 else => {
1616 @compileError("isFinite not implemented for " ++ @typeName(T));
std/math/isinf.zig+6-6
......@@ -6,11 +6,11 @@ pub fn isInf(x: var) -> bool {
66 switch (T) {
77 f32 => {
88 const bits = @bitCast(u32, x);
9 bits & 0x7FFFFFFF == 0x7F800000
9 return bits & 0x7FFFFFFF == 0x7F800000;
1010 },
1111 f64 => {
1212 const bits = @bitCast(u64, x);
13 bits & (@maxValue(u64) >> 1) == (0x7FF << 52)
13 return bits & (@maxValue(u64) >> 1) == (0x7FF << 52);
1414 },
1515 else => {
1616 @compileError("isInf not implemented for " ++ @typeName(T));
......@@ -22,10 +22,10 @@ pub fn isPositiveInf(x: var) -> bool {
2222 const T = @typeOf(x);
2323 switch (T) {
2424 f32 => {
25 @bitCast(u32, x) == 0x7F800000
25 return @bitCast(u32, x) == 0x7F800000;
2626 },
2727 f64 => {
28 @bitCast(u64, x) == 0x7FF << 52
28 return @bitCast(u64, x) == 0x7FF << 52;
2929 },
3030 else => {
3131 @compileError("isPositiveInf not implemented for " ++ @typeName(T));
......@@ -37,10 +37,10 @@ pub fn isNegativeInf(x: var) -> bool {
3737 const T = @typeOf(x);
3838 switch (T) {
3939 f32 => {
40 @bitCast(u32, x) == 0xFF800000
40 return @bitCast(u32, x) == 0xFF800000;
4141 },
4242 f64 => {
43 @bitCast(u64, x) == 0xFFF << 52
43 return @bitCast(u64, x) == 0xFFF << 52;
4444 },
4545 else => {
4646 @compileError("isNegativeInf not implemented for " ++ @typeName(T));
std/math/isnan.zig+3-3
......@@ -6,11 +6,11 @@ pub fn isNan(x: var) -> bool {
66 switch (T) {
77 f32 => {
88 const bits = @bitCast(u32, x);
9 bits & 0x7FFFFFFF > 0x7F800000
9 return bits & 0x7FFFFFFF > 0x7F800000;
1010 },
1111 f64 => {
1212 const bits = @bitCast(u64, x);
13 (bits & (@maxValue(u64) >> 1)) > (u64(0x7FF) << 52)
13 return (bits & (@maxValue(u64) >> 1)) > (u64(0x7FF) << 52);
1414 },
1515 else => {
1616 @compileError("isNan not implemented for " ++ @typeName(T));
......@@ -21,7 +21,7 @@ pub fn isNan(x: var) -> bool {
2121// Note: A signalling nan is identical to a standard right now by may have a different bit
2222// representation in the future when required.
2323pub fn isSignalNan(x: var) -> bool {
24 isNan(x)
24 return isNan(x);
2525}
2626
2727test "math.isNan" {
std/math/isnormal.zig+2-2
......@@ -6,11 +6,11 @@ pub fn isNormal(x: var) -> bool {
66 switch (T) {
77 f32 => {
88 const bits = @bitCast(u32, x);
9 (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000
9 return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000;
1010 },
1111 f64 => {
1212 const bits = @bitCast(u64, x);
13 (bits + (1 << 52)) & (@maxValue(u64) >> 1) >= (1 << 53)
13 return (bits + (1 << 52)) & (@maxValue(u64) >> 1) >= (1 << 53);
1414 },
1515 else => {
1616 @compileError("isNormal not implemented for " ++ @typeName(T));
std/math/ln.zig+4-4
......@@ -14,7 +14,7 @@ pub fn ln(x: var) -> @typeOf(x) {
1414 const T = @typeOf(x);
1515 switch (@typeId(T)) {
1616 TypeId.FloatLiteral => {
17 return @typeOf(1.0)(ln_64(x))
17 return @typeOf(1.0)(ln_64(x));
1818 },
1919 TypeId.Float => {
2020 return switch (T) {
......@@ -84,7 +84,7 @@ pub fn ln_32(x_: f32) -> f32 {
8484 const hfsq = 0.5 * f * f;
8585 const dk = f32(k);
8686
87 s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi
87 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
8888}
8989
9090pub fn ln_64(x_: f64) -> f64 {
......@@ -116,7 +116,7 @@ pub fn ln_64(x_: f64) -> f64 {
116116 // subnormal, scale x
117117 k -= 54;
118118 x *= 0x1.0p54;
119 hx = u32(@bitCast(u64, ix) >> 32)
119 hx = u32(@bitCast(u64, ix) >> 32);
120120 }
121121 else if (hx >= 0x7FF00000) {
122122 return x;
......@@ -142,7 +142,7 @@ pub fn ln_64(x_: f64) -> f64 {
142142 const R = t2 + t1;
143143 const dk = f64(k);
144144
145 s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi
145 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
146146}
147147
148148test "math.ln" {
std/math/log.zig+1-1
......@@ -29,7 +29,7 @@ pub fn log(comptime T: type, base: T, x: T) -> T {
2929 f32 => return f32(math.ln(f64(x)) / math.ln(f64(base))),
3030 f64 => return math.ln(x) / math.ln(f64(base)),
3131 else => @compileError("log not implemented for " ++ @typeName(T)),
32 };
32 }
3333 },
3434
3535 else => {
std/math/log10.zig+4-4
......@@ -14,7 +14,7 @@ pub fn log10(x: var) -> @typeOf(x) {
1414 const T = @typeOf(x);
1515 switch (@typeId(T)) {
1616 TypeId.FloatLiteral => {
17 return @typeOf(1.0)(log10_64(x))
17 return @typeOf(1.0)(log10_64(x));
1818 },
1919 TypeId.Float => {
2020 return switch (T) {
......@@ -90,7 +90,7 @@ pub fn log10_32(x_: f32) -> f32 {
9090 const lo = f - hi - hfsq + s * (hfsq + R);
9191 const dk = f32(k);
9292
93 dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi
93 return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi;
9494}
9595
9696pub fn log10_64(x_: f64) -> f64 {
......@@ -124,7 +124,7 @@ pub fn log10_64(x_: f64) -> f64 {
124124 // subnormal, scale x
125125 k -= 54;
126126 x *= 0x1.0p54;
127 hx = u32(@bitCast(u64, x) >> 32)
127 hx = u32(@bitCast(u64, x) >> 32);
128128 }
129129 else if (hx >= 0x7FF00000) {
130130 return x;
......@@ -167,7 +167,7 @@ pub fn log10_64(x_: f64) -> f64 {
167167 val_lo += (y - ww) + val_hi;
168168 val_hi = ww;
169169
170 val_lo + val_hi
170 return val_lo + val_hi;
171171}
172172
173173test "math.log10" {
std/math/log1p.zig+6-6
......@@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert;
1111
1212pub fn log1p(x: var) -> @typeOf(x) {
1313 const T = @typeOf(x);
14 switch (T) {
15 f32 => @inlineCall(log1p_32, x),
16 f64 => @inlineCall(log1p_64, x),
14 return switch (T) {
15 f32 => log1p_32(x),
16 f64 => log1p_64(x),
1717 else => @compileError("log1p not implemented for " ++ @typeName(T)),
18 }
18 };
1919}
2020
2121fn log1p_32(x: f32) -> f32 {
......@@ -91,7 +91,7 @@ fn log1p_32(x: f32) -> f32 {
9191 const hfsq = 0.5 * f * f;
9292 const dk = f32(k);
9393
94 s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
94 return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
9595}
9696
9797fn log1p_64(x: f64) -> f64 {
......@@ -172,7 +172,7 @@ fn log1p_64(x: f64) -> f64 {
172172 const R = t2 + t1;
173173 const dk = f64(k);
174174
175 s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
175 return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
176176}
177177
178178test "math.log1p" {
std/math/log2.zig+4-4
......@@ -14,7 +14,7 @@ pub fn log2(x: var) -> @typeOf(x) {
1414 const T = @typeOf(x);
1515 switch (@typeId(T)) {
1616 TypeId.FloatLiteral => {
17 return @typeOf(1.0)(log2_64(x))
17 return @typeOf(1.0)(log2_64(x));
1818 },
1919 TypeId.Float => {
2020 return switch (T) {
......@@ -26,7 +26,7 @@ pub fn log2(x: var) -> @typeOf(x) {
2626 TypeId.IntLiteral => comptime {
2727 var result = 0;
2828 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) {}
3030 return result;
3131 },
3232 TypeId.Int => {
......@@ -94,7 +94,7 @@ pub fn log2_32(x_: f32) -> f32 {
9494 u &= 0xFFFFF000;
9595 hi = @bitCast(f32, u);
9696 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);
9898}
9999
100100pub fn log2_64(x_: f64) -> f64 {
......@@ -165,7 +165,7 @@ pub fn log2_64(x_: f64) -> f64 {
165165 val_lo += (y - ww) + val_hi;
166166 val_hi = ww;
167167
168 val_lo + val_hi
168 return val_lo + val_hi;
169169}
170170
171171test "math.log2" {
std/math/modf.zig+8-8
......@@ -7,21 +7,21 @@ const math = @import("index.zig");
77const assert = @import("../debug.zig").assert;
88
99fn modf_result(comptime T: type) -> type {
10 struct {
10 return struct {
1111 fpart: T,
1212 ipart: T,
13 }
13 };
1414}
1515pub const modf32_result = modf_result(f32);
1616pub const modf64_result = modf_result(f64);
1717
1818pub fn modf(x: var) -> modf_result(@typeOf(x)) {
1919 const T = @typeOf(x);
20 switch (T) {
21 f32 => @inlineCall(modf32, x),
22 f64 => @inlineCall(modf64, x),
20 return switch (T) {
21 f32 => modf32(x),
22 f64 => modf64(x),
2323 else => @compileError("modf not implemented for " ++ @typeName(T)),
24 }
24 };
2525}
2626
2727fn modf32(x: f32) -> modf32_result {
......@@ -66,7 +66,7 @@ fn modf32(x: f32) -> modf32_result {
6666 const uf = @bitCast(f32, u & ~mask);
6767 result.ipart = uf;
6868 result.fpart = x - uf;
69 result
69 return result;
7070}
7171
7272fn modf64(x: f64) -> modf64_result {
......@@ -110,7 +110,7 @@ fn modf64(x: f64) -> modf64_result {
110110 const uf = @bitCast(f64, u & ~mask);
111111 result.ipart = uf;
112112 result.fpart = x - uf;
113 result
113 return result;
114114}
115115
116116test "math.modf" {
std/math/nan.zig+4-4
......@@ -1,19 +1,19 @@
11const math = @import("index.zig");
22
33pub fn nan(comptime T: type) -> T {
4 switch (T) {
4 return switch (T) {
55 f32 => @bitCast(f32, math.nan_u32),
66 f64 => @bitCast(f64, math.nan_u64),
77 else => @compileError("nan not implemented for " ++ @typeName(T)),
8 }
8 };
99}
1010
1111// Note: A signalling nan is identical to a standard right now by may have a different bit
1212// representation in the future when required.
1313pub fn snan(comptime T: type) -> T {
14 switch (T) {
14 return switch (T) {
1515 f32 => @bitCast(f32, math.nan_u32),
1616 f64 => @bitCast(f64, math.nan_u64),
1717 else => @compileError("snan not implemented for " ++ @typeName(T)),
18 }
18 };
1919}
std/math/pow.zig+2-2
......@@ -166,12 +166,12 @@ pub fn pow(comptime T: type, x: T, y: T) -> T {
166166 ae = -ae;
167167 }
168168
169 math.scalbn(a1, ae)
169 return math.scalbn(a1, ae);
170170}
171171
172172fn isOddInteger(x: f64) -> bool {
173173 const r = math.modf(x);
174 r.fpart == 0.0 and i64(r.ipart) & 1 == 1
174 return r.fpart == 0.0 and i64(r.ipart) & 1 == 1;
175175}
176176
177177test "math.pow" {
std/math/round.zig+8-8
......@@ -10,11 +10,11 @@ const math = @import("index.zig");
1010
1111pub fn round(x: var) -> @typeOf(x) {
1212 const T = @typeOf(x);
13 switch (T) {
14 f32 => @inlineCall(round32, x),
15 f64 => @inlineCall(round64, x),
13 return switch (T) {
14 f32 => round32(x),
15 f64 => round64(x),
1616 else => @compileError("round not implemented for " ++ @typeName(T)),
17 }
17 };
1818}
1919
2020fn round32(x_: f32) -> f32 {
......@@ -48,9 +48,9 @@ fn round32(x_: f32) -> f32 {
4848 }
4949
5050 if (u >> 31 != 0) {
51 -y
51 return -y;
5252 } else {
53 y
53 return y;
5454 }
5555}
5656
......@@ -85,9 +85,9 @@ fn round64(x_: f64) -> f64 {
8585 }
8686
8787 if (u >> 63 != 0) {
88 -y
88 return -y;
8989 } else {
90 y
90 return y;
9191 }
9292}
9393
std/math/scalbn.zig+6-6
......@@ -3,11 +3,11 @@ const assert = @import("../debug.zig").assert;
33
44pub fn scalbn(x: var, n: i32) -> @typeOf(x) {
55 const T = @typeOf(x);
6 switch (T) {
7 f32 => @inlineCall(scalbn32, x, n),
8 f64 => @inlineCall(scalbn64, x, n),
6 return switch (T) {
7 f32 => scalbn32(x, n),
8 f64 => scalbn64(x, n),
99 else => @compileError("scalbn not implemented for " ++ @typeName(T)),
10 }
10 };
1111}
1212
1313fn scalbn32(x: f32, n_: i32) -> f32 {
......@@ -37,7 +37,7 @@ fn scalbn32(x: f32, n_: i32) -> f32 {
3737 }
3838
3939 const u = u32(n +% 0x7F) << 23;
40 y * @bitCast(f32, u)
40 return y * @bitCast(f32, u);
4141}
4242
4343fn scalbn64(x: f64, n_: i32) -> f64 {
......@@ -67,7 +67,7 @@ fn scalbn64(x: f64, n_: i32) -> f64 {
6767 }
6868
6969 const u = u64(n +% 0x3FF) << 52;
70 y * @bitCast(f64, u)
70 return y * @bitCast(f64, u);
7171}
7272
7373test "math.scalbn" {
std/math/signbit.zig+6-6
......@@ -3,21 +3,21 @@ const assert = @import("../debug.zig").assert;
33
44pub fn signbit(x: var) -> bool {
55 const T = @typeOf(x);
6 switch (T) {
7 f32 => @inlineCall(signbit32, x),
8 f64 => @inlineCall(signbit64, x),
6 return switch (T) {
7 f32 => signbit32(x),
8 f64 => signbit64(x),
99 else => @compileError("signbit not implemented for " ++ @typeName(T)),
10 }
10 };
1111}
1212
1313fn signbit32(x: f32) -> bool {
1414 const bits = @bitCast(u32, x);
15 bits >> 31 != 0
15 return bits >> 31 != 0;
1616}
1717
1818fn signbit64(x: f64) -> bool {
1919 const bits = @bitCast(u64, x);
20 bits >> 63 != 0
20 return bits >> 63 != 0;
2121}
2222
2323test "math.signbit" {
std/math/sin.zig+15-15
......@@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert;
1010
1111pub fn sin(x: var) -> @typeOf(x) {
1212 const T = @typeOf(x);
13 switch (T) {
14 f32 => @inlineCall(sin32, x),
15 f64 => @inlineCall(sin64, x),
13 return switch (T) {
14 f32 => sin32(x),
15 f64 => sin64(x),
1616 else => @compileError("sin not implemented for " ++ @typeName(T)),
17 }
17 };
1818}
1919
2020// sin polynomial coefficients
......@@ -75,18 +75,18 @@ fn sin32(x_: f32) -> f32 {
7575 const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
7676 const w = z * z;
7777
78 const r = {
78 const r = r: {
7979 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)))));
8181 } 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)))));
8383 }
8484 };
8585
8686 if (sign) {
87 -r
87 return -r;
8888 } else {
89 r
89 return r;
9090 }
9191}
9292
......@@ -127,25 +127,25 @@ fn sin64(x_: f64) -> f64 {
127127 const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
128128 const w = z * z;
129129
130 const r = {
130 const r = r: {
131131 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)))));
133133 } 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)))));
135135 }
136136 };
137137
138138 if (sign) {
139 -r
139 return -r;
140140 } else {
141 r
141 return r;
142142 }
143143}
144144
145145test "math.sin" {
146146 assert(sin(f32(0.0)) == sin32(0.0));
147147 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)));
149149}
150150
151151test "math.sin32" {
std/math/sinh.zig+6-6
......@@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2;
1111
1212pub fn sinh(x: var) -> @typeOf(x) {
1313 const T = @typeOf(x);
14 switch (T) {
15 f32 => @inlineCall(sinh32, x),
16 f64 => @inlineCall(sinh64, x),
14 return switch (T) {
15 f32 => sinh32(x),
16 f64 => sinh64(x),
1717 else => @compileError("sinh not implemented for " ++ @typeName(T)),
18 }
18 };
1919}
2020
2121// sinh(x) = (exp(x) - 1 / exp(x)) / 2
......@@ -49,7 +49,7 @@ fn sinh32(x: f32) -> f32 {
4949 }
5050
5151 // |x| > log(FLT_MAX) or nan
52 2 * h * expo2(ax)
52 return 2 * h * expo2(ax);
5353}
5454
5555fn sinh64(x: f64) -> f64 {
......@@ -83,7 +83,7 @@ fn sinh64(x: f64) -> f64 {
8383 }
8484
8585 // |x| > log(DBL_MAX) or nan
86 2 * h * expo2(ax)
86 return 2 * h * expo2(ax);
8787}
8888
8989test "math.sinh" {
std/math/sqrt.zig+62-8
......@@ -7,12 +7,34 @@
77
88const math = @import("index.zig");
99const 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)) {
1214 const T = @typeOf(x);
13 switch (T) {
14 f32 => @inlineCall(sqrt32, x),
15 f64 => @inlineCall(sqrt64, x),
15 switch (@typeId(T)) {
16 TypeId.FloatLiteral => {
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 },
1638 else => @compileError("sqrt not implemented for " ++ @typeName(T)),
1739 }
1840}
......@@ -42,7 +64,7 @@ fn sqrt32(x: f32) -> f32 {
4264 // subnormal
4365 var i: i32 = 0;
4466 while (ix & 0x00800000 == 0) : (i += 1) {
45 ix <<= 1
67 ix <<= 1;
4668 }
4769 m -= i - 1;
4870 }
......@@ -90,7 +112,7 @@ fn sqrt32(x: f32) -> f32 {
90112
91113 ix = (q >> 1) + 0x3f000000;
92114 ix += m << 23;
93 @bitCast(f32, ix)
115 return @bitCast(f32, ix);
94116}
95117
96118// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
......@@ -131,7 +153,7 @@ fn sqrt64(x: f64) -> f64 {
131153 // subnormal
132154 var i: u32 = 0;
133155 while (ix0 & 0x00100000 == 0) : (i += 1) {
134 ix0 <<= 1
156 ix0 <<= 1;
135157 }
136158 m -= i32(i) - 1;
137159 ix0 |= ix1 >> u5(32 - i);
......@@ -223,7 +245,7 @@ fn sqrt64(x: f64) -> f64 {
223245 iix0 = iix0 +% (m << 20);
224246
225247 const uz = (u64(iix0) << 32) | ix1;
226 @bitCast(f64, uz)
248 return @bitCast(f64, uz);
227249}
228250
229251test "math.sqrt" {
......@@ -274,3 +296,35 @@ test "math.sqrt64.special" {
274296 assert(math.isNan(sqrt64(-1.0)));
275297 assert(math.isNan(sqrt64(math.nan(f64))));
276298}
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;
1010
1111pub fn tan(x: var) -> @typeOf(x) {
1212 const T = @typeOf(x);
13 switch (T) {
14 f32 => @inlineCall(tan32, x),
15 f64 => @inlineCall(tan64, x),
13 return switch (T) {
14 f32 => tan32(x),
15 f64 => tan64(x),
1616 else => @compileError("tan not implemented for " ++ @typeName(T)),
17 }
17 };
1818}
1919
2020const Tp0 = -1.30936939181383777646E4;
......@@ -62,11 +62,11 @@ fn tan32(x_: f32) -> f32 {
6262 const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
6363 const w = z * z;
6464
65 var r = {
65 var r = r: {
6666 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));
6868 } else {
69 z
69 break :r z;
7070 }
7171 };
7272
......@@ -77,7 +77,7 @@ fn tan32(x_: f32) -> f32 {
7777 r = -r;
7878 }
7979
80 r
80 return r;
8181}
8282
8383fn tan64(x_: f64) -> f64 {
......@@ -111,11 +111,11 @@ fn tan64(x_: f64) -> f64 {
111111 const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
112112 const w = z * z;
113113
114 var r = {
114 var r = r: {
115115 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));
117117 } else {
118 z
118 break :r z;
119119 }
120120 };
121121
......@@ -126,7 +126,7 @@ fn tan64(x_: f64) -> f64 {
126126 r = -r;
127127 }
128128
129 r
129 return r;
130130}
131131
132132test "math.tan" {
std/math/tanh.zig+8-8
......@@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2;
1111
1212pub fn tanh(x: var) -> @typeOf(x) {
1313 const T = @typeOf(x);
14 switch (T) {
15 f32 => @inlineCall(tanh32, x),
16 f64 => @inlineCall(tanh64, x),
14 return switch (T) {
15 f32 => tanh32(x),
16 f64 => tanh64(x),
1717 else => @compileError("tanh not implemented for " ++ @typeName(T)),
18 }
18 };
1919}
2020
2121// tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
......@@ -59,9 +59,9 @@ fn tanh32(x: f32) -> f32 {
5959 }
6060
6161 if (u >> 31 != 0) {
62 -t
62 return -t;
6363 } else {
64 t
64 return t;
6565 }
6666}
6767
......@@ -104,9 +104,9 @@ fn tanh64(x: f64) -> f64 {
104104 }
105105
106106 if (u >> 63 != 0) {
107 -t
107 return -t;
108108 } else {
109 t
109 return t;
110110 }
111111}
112112
std/math/trunc.zig+8-8
......@@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
99
1010pub fn trunc(x: var) -> @typeOf(x) {
1111 const T = @typeOf(x);
12 switch (T) {
13 f32 => @inlineCall(trunc32, x),
14 f64 => @inlineCall(trunc64, x),
12 return switch (T) {
13 f32 => trunc32(x),
14 f64 => trunc64(x),
1515 else => @compileError("trunc not implemented for " ++ @typeName(T)),
16 }
16 };
1717}
1818
1919fn trunc32(x: f32) -> f32 {
......@@ -30,10 +30,10 @@ fn trunc32(x: f32) -> f32 {
3030
3131 m = u32(@maxValue(u32)) >> u5(e);
3232 if (u & m == 0) {
33 x
33 return x;
3434 } else {
3535 math.forceEval(x + 0x1p120);
36 @bitCast(f32, u & ~m)
36 return @bitCast(f32, u & ~m);
3737 }
3838}
3939
......@@ -51,10 +51,10 @@ fn trunc64(x: f64) -> f64 {
5151
5252 m = u64(@maxValue(u64)) >> u6(e);
5353 if (u & m == 0) {
54 x
54 return x;
5555 } else {
5656 math.forceEval(x + 0x1p120);
57 @bitCast(f64, u & ~m)
57 return @bitCast(f64, u & ~m);
5858 }
5959}
6060
std/mem.zig+149-36
......@@ -3,26 +3,31 @@ const assert = debug.assert;
33const math = @import("math/index.zig");
44const builtin = @import("builtin");
55
6pub const Cmp = math.Cmp;
6error OutOfMemory;
77
88pub const Allocator = struct {
99 /// Allocate byte_count bytes and return them in a slice, with the
10 /// slicer's pointer aligned at least to alignment bytes.
11 allocFn: fn (self: &Allocator, byte_count: usize, alignment: usize) -> %[]u8,
10 /// slice's pointer aligned at least to alignment bytes.
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 /// Guaranteed: alignment >= alignment of old_mem.ptr
14 /// If `new_byte_count > old_mem.len`:
15 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
16 /// * alignment >= alignment of old_mem.ptr
1517 ///
16 /// If `new_byte_count` is less than or equal to `old_mem.len` this function must
17 /// return successfully.
18 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: usize) -> %[]u8,
18 /// If `new_byte_count <= old_mem.len`:
19 /// * this function must return successfully.
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
2025 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
2126 freeFn: fn (self: &Allocator, old_mem: []u8),
2227
2328 fn create(self: &Allocator, comptime T: type) -> %&T {
2429 const slice = %return self.alloc(T, 1);
25 &slice[0]
30 return &slice[0];
2631 }
2732
2833 fn destroy(self: &Allocator, ptr: var) {
......@@ -30,28 +35,52 @@ pub const Allocator = struct {
3035 }
3136
3237 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 {
3344 const byte_count = %return math.mul(usize, @sizeOf(T), n);
34 const byte_slice = %return self.allocFn(self, byte_count, @alignOf(T));
35 ([]T)(@alignCast(@alignOf(T), byte_slice))
45 const byte_slice = %return self.allocFn(self, byte_count, alignment);
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));
3651 }
3752
3853 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 {
3960 if (old_mem.len == 0) {
4061 return self.alloc(T, n);
4162 }
4263
43 // Assert that old_mem.ptr is properly aligned.
44 const aligned_old_mem = @alignCast(@alignOf(T), old_mem);
45
64 const old_byte_slice = ([]u8)(old_mem);
4665 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));
48 return ([]T)(@alignCast(@alignOf(T), byte_slice));
66 const byte_slice = %return self.reallocFn(self, old_byte_slice, byte_count, alignment);
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));
4972 }
5073
5174 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.
5275 /// Unlike `realloc`, this function cannot fail.
5376 /// Shrinking to 0 is the same as calling `free`.
5477 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 {
5584 if (n == 0) {
5685 self.free(old_mem);
5786 return old_mem[0..0];
......@@ -59,15 +88,12 @@ pub const Allocator = struct {
5988
6089 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
6591 // Here we skip the overflow checking on the multiplication because
6692 // n <= old_mem.len and the multiplication didn't overflow for that operation.
6793 const byte_count = @sizeOf(T) * n;
6894
69 const byte_slice = %%self.reallocFn(self, ([]u8)(aligned_old_mem), byte_count, @alignOf(T));
70 return ([]T)(@alignCast(@alignOf(T), byte_slice));
95 const byte_slice = %%self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment);
96 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
7197 }
7298
7399 fn free(self: &Allocator, memory: var) {
......@@ -79,6 +105,51 @@ pub const Allocator = struct {
79105 }
80106};
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
83154/// Copy all of source into dest at position 0.
84155/// dest.len must be >= source.len.
......@@ -95,17 +166,24 @@ pub fn set(comptime T: type, dest: []T, value: T) {
95166 for (dest) |*d| *d = value;
96167}
97168
98/// Return < 0, == 0, or > 0 if memory a is less than, equal to, or greater than,
99/// memory b, respectively.
100pub fn cmp(comptime T: type, a: []const T, b: []const T) -> Cmp {
101 const n = math.min(a.len, b.len);
169/// Returns true if lhs < rhs, false otherwise
170pub fn lessThan(comptime T: type, lhs: []const T, rhs: []const T) -> bool {
171 const n = math.min(lhs.len, rhs.len);
102172 var i: usize = 0;
103173 while (i < n) : (i += 1) {
104 if (a[i] == b[i]) continue;
105 return if (a[i] > b[i]) Cmp.Greater else if (a[i] < b[i]) Cmp.Less else Cmp.Equal;
174 if (lhs[i] == rhs[i]) continue;
175 return lhs[i] < rhs[i];
106176 }
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"));
109187}
110188
111189/// 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 {
276354/// split(" abc def ghi ", " ")
277355/// Will return slices for "abc", "def", "ghi", null, in that order.
278356pub fn split(buffer: []const u8, split_bytes: []const u8) -> SplitIterator {
279 SplitIterator {
357 return SplitIterator {
280358 .index = 0,
281359 .buffer = buffer,
282360 .split_bytes = split_bytes,
283 }
361 };
284362}
285363
286364test "mem.split" {
......@@ -433,9 +511,8 @@ fn testWriteIntImpl() {
433511
434512pub fn min(comptime T: type, slice: []const T) -> T {
435513 var best = slice[0];
436 var i: usize = 1;
437 while (i < slice.len) : (i += 1) {
438 best = math.min(best, slice[i]);
514 for (slice[1..]) |item| {
515 best = math.min(best, item);
439516 }
440517 return best;
441518}
......@@ -446,9 +523,8 @@ test "mem.min" {
446523
447524pub fn max(comptime T: type, slice: []const T) -> T {
448525 var best = slice[0];
449 var i: usize = 1;
450 while (i < slice.len) : (i += 1) {
451 best = math.max(best, slice[i]);
526 for (slice[1..]) |item| {
527 best = math.max(best, item);
452528 }
453529 return best;
454530}
......@@ -456,3 +532,40 @@ pub fn max(comptime T: type, slice: []const T) -> T {
456532test "mem.max" {
457533 assert(max(u8, "abcdefg") == 'g');
458534}
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 {
7272// if (family != AF_INET)
7373// buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
7474//
75 unreachable // TODO
75 unreachable; // TODO
7676 }
7777
7878 // TODO
......@@ -84,7 +84,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
8484 // else => {},
8585 //};
8686
87 unreachable // TODO
87 unreachable; // TODO
8888}
8989
9090pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
......@@ -96,23 +96,23 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
9696 }
9797 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: {
100100 var os_addr: linux.sockaddr_in = undefined;
101101 os_addr.family = addr.family;
102102 os_addr.port = endian.swapIfLe(u16, port);
103103 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
104104 @memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero)));
105 linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in))
106 } else if (addr.family == linux.AF_INET6) {
105 break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in));
106 } else if (addr.family == linux.AF_INET6) x: {
107107 var os_addr: linux.sockaddr_in6 = undefined;
108108 os_addr.family = addr.family;
109109 os_addr.port = endian.swapIfLe(u16, port);
110110 os_addr.flowinfo = 0;
111111 os_addr.scope_id = addr.scope_id;
112112 @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));
114114 } else {
115 unreachable
115 unreachable;
116116 };
117117 const connect_err = linux.getErrno(connect_ret);
118118 if (connect_err > 0) {
......@@ -165,13 +165,13 @@ pub fn parseIpLiteral(buf: []const u8) -> %Address {
165165fn hexDigit(c: u8) -> u8 {
166166 // TODO use switch with range
167167 if ('0' <= c and c <= '9') {
168 c - '0'
168 return c - '0';
169169 } else if ('A' <= c and c <= 'Z') {
170 c - 'A' + 10
170 return c - 'A' + 10;
171171 } else if ('a' <= c and c <= 'z') {
172 c - 'a' + 10
172 return c - 'a' + 10;
173173 } else {
174 @maxValue(u8)
174 return @maxValue(u8);
175175 }
176176}
177177
std/os/child_process.zig+82-40
......@@ -5,7 +5,6 @@ const os = std.os;
55const posix = os.posix;
66const windows = os.windows;
77const mem = std.mem;
8const Allocator = mem.Allocator;
98const debug = std.debug;
109const assert = debug.assert;
1110const BufMap = std.BufMap;
......@@ -74,7 +73,7 @@ pub const ChildProcess = struct {
7473
7574 /// First argument in argv is the executable.
7675 /// 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 {
7877 const child = %return allocator.create(ChildProcess);
7978 %defer allocator.destroy(child);
8079
......@@ -116,7 +115,7 @@ pub const ChildProcess = struct {
116115 return self.spawnWindows();
117116 } else {
118117 return self.spawnPosix();
119 };
118 }
120119 }
121120
122121 pub fn spawnAndWait(self: &ChildProcess) -> %Term {
......@@ -180,6 +179,46 @@ pub const ChildProcess = struct {
180179 }
181180 }
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
183222 fn waitWindows(self: &ChildProcess) -> %Term {
184223 if (self.term) |term| {
185224 self.cleanupStreams();
......@@ -210,12 +249,12 @@ pub const ChildProcess = struct {
210249 fn waitUnwrappedWindows(self: &ChildProcess) -> %void {
211250 const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
212251
213 self.term = (%Term)({
252 self.term = (%Term)(x: {
214253 var exit_code: windows.DWORD = undefined;
215254 if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
216 Term { .Unknown = 0 }
255 break :x Term { .Unknown = 0 };
217256 } else {
218 Term { .Exited = @bitCast(i32, exit_code)}
257 break :x Term { .Exited = @bitCast(i32, exit_code)};
219258 }
220259 });
221260
......@@ -261,7 +300,7 @@ pub const ChildProcess = struct {
261300 defer {
262301 os.close(self.err_pipe[0]);
263302 os.close(self.err_pipe[1]);
264 };
303 }
265304
266305 // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after
267306 // waitpid, so this write is guaranteed to be after the child
......@@ -280,15 +319,15 @@ pub const ChildProcess = struct {
280319 }
281320
282321 fn statusToTerm(status: i32) -> Term {
283 return if (posix.WIFEXITED(status)) {
322 return if (posix.WIFEXITED(status))
284323 Term { .Exited = posix.WEXITSTATUS(status) }
285 } else if (posix.WIFSIGNALED(status)) {
324 else if (posix.WIFSIGNALED(status))
286325 Term { .Signal = posix.WTERMSIG(status) }
287 } else if (posix.WIFSTOPPED(status)) {
326 else if (posix.WIFSTOPPED(status))
288327 Term { .Stopped = posix.WSTOPSIG(status) }
289 } else {
328 else
290329 Term { .Unknown = status }
291 };
330 ;
292331 }
293332
294333 fn spawnPosix(self: &ChildProcess) -> %void {
......@@ -305,22 +344,22 @@ pub const ChildProcess = struct {
305344 %defer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
306345
307346 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)
309348 %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null)
310 } else {
349 else
311350 undefined
312 };
313 defer { if (any_ignore) os.close(dev_null_fd); };
351 ;
352 defer { if (any_ignore) os.close(dev_null_fd); }
314353
315354 var env_map_owned: BufMap = undefined;
316355 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: {
318357 we_own_env_map = false;
319 env_map
320 } else {
358 break :x env_map;
359 } else x: {
321360 we_own_env_map = true;
322361 env_map_owned = %return os.getEnvMap(self.allocator);
323 &env_map_owned
362 break :x &env_map_owned;
324363 };
325364 defer { if (we_own_env_map) env_map_owned.deinit(); }
326365
......@@ -411,13 +450,13 @@ pub const ChildProcess = struct {
411450 self.stdout_behavior == StdIo.Ignore or
412451 self.stderr_behavior == StdIo.Ignore);
413452
414 const nul_handle = if (any_ignore) {
453 const nul_handle = if (any_ignore)
415454 %return os.windowsOpen("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,
416455 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null)
417 } else {
456 else
418457 undefined
419 };
420 defer { if (any_ignore) os.close(nul_handle); };
458 ;
459 defer { if (any_ignore) os.close(nul_handle); }
421460 if (any_ignore) {
422461 %return windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
423462 }
......@@ -503,30 +542,32 @@ pub const ChildProcess = struct {
503542 };
504543 var piProcInfo: windows.PROCESS_INFORMATION = undefined;
505544
506 const cwd_slice = if (self.cwd) |cwd| {
545 const cwd_slice = if (self.cwd) |cwd|
507546 %return cstr.addNullByte(self.allocator, cwd)
508 } else {
547 else
509548 null
510 };
549 ;
511550 defer if (cwd_slice) |cwd| self.allocator.free(cwd);
512551 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|
515554 %return os.createWindowsEnvBlock(self.allocator, env_map)
516 } else {
555 else
517556 null
518 };
557 ;
519558 defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
520559 const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
521560
522561 // the cwd set in ChildProcess is in effect when choosing the executable path
523562 // to match posix semantics
524 const app_name = if (self.cwd) |cwd| {
525 const resolved = %return os.path.resolve(self.allocator, cwd, self.argv[0]);
526 defer self.allocator.free(resolved);
527 %return cstr.addNullByte(self.allocator, resolved)
528 } else {
529 %return cstr.addNullByte(self.allocator, self.argv[0])
563 const app_name = x: {
564 if (self.cwd) |cwd| {
565 const resolved = %return os.path.resolve(self.allocator, cwd, self.argv[0]);
566 defer self.allocator.free(resolved);
567 break :x %return cstr.addNullByte(self.allocator, resolved);
568 } else {
569 break :x %return cstr.addNullByte(self.allocator, self.argv[0]);
570 }
530571 };
531572 defer self.allocator.free(app_name);
532573
......@@ -589,6 +630,7 @@ pub const ChildProcess = struct {
589630 StdIo.Ignore => %return os.posixDup2(dev_null_fd, std_fileno),
590631 }
591632 }
633
592634};
593635
594636fn 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: ?
611653
612654/// Caller must dealloc.
613655/// 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 {
615657 var buf = %return Buffer.initSize(allocator, 0);
616658 defer buf.deinit();
617659
......@@ -701,7 +743,7 @@ fn makePipe() -> %[2]i32 {
701743 return switch (err) {
702744 posix.EMFILE, posix.ENFILE => error.SystemResources,
703745 else => os.unexpectedErrorPosix(err),
704 }
746 };
705747 }
706748 return fds;
707749}
......@@ -760,10 +802,10 @@ fn handleTerm(pid: i32, status: i32) {
760802 }
761803}
762804
763const sigchld_set = {
805const sigchld_set = x: {
764806 var signal_set = posix.empty_sigset;
765807 posix.sigaddset(&signal_set, posix.SIGCHLD);
766 signal_set
808 break :x signal_set;
767809};
768810
769811fn block_SIGCHLD() {
std/os/darwin.zig+38-42
......@@ -97,63 +97,63 @@ pub const SIGINFO = 29; /// information request
9797pub const SIGUSR1 = 30; /// user defined signal 1
9898pub const SIGUSR2 = 31; /// user defined signal 2
9999
100fn wstatus(x: i32) -> i32 { x & 0o177 }
100fn wstatus(x: i32) -> i32 { return x & 0o177; }
101101const wstopped = 0o177;
102pub fn WEXITSTATUS(x: i32) -> i32 { x >> 8 }
103pub fn WTERMSIG(x: i32) -> i32 { wstatus(x) }
104pub fn WSTOPSIG(x: i32) -> i32 { x >> 8 }
105pub fn WIFEXITED(x: i32) -> bool { wstatus(x) == 0 }
106pub fn WIFSTOPPED(x: i32) -> bool { wstatus(x) == wstopped and WSTOPSIG(x) != 0x13 }
107pub fn WIFSIGNALED(x: i32) -> bool { wstatus(x) != wstopped and wstatus(x) != 0 }
102pub fn WEXITSTATUS(x: i32) -> i32 { return x >> 8; }
103pub fn WTERMSIG(x: i32) -> i32 { return wstatus(x); }
104pub fn WSTOPSIG(x: i32) -> i32 { return x >> 8; }
105pub fn WIFEXITED(x: i32) -> bool { return wstatus(x) == 0; }
106pub fn WIFSTOPPED(x: i32) -> bool { return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; }
107pub fn WIFSIGNALED(x: i32) -> bool { return wstatus(x) != wstopped and wstatus(x) != 0; }
108108
109109/// Get the errno from a syscall return value, or 0 for no error.
110110pub fn getErrno(r: usize) -> usize {
111111 const signed_r = @bitCast(isize, r);
112 if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0
112 return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
113113}
114114
115115pub fn close(fd: i32) -> usize {
116 errnoWrap(c.close(fd))
116 return errnoWrap(c.close(fd));
117117}
118118
119119pub fn abort() -> noreturn {
120 c.abort()
120 c.abort();
121121}
122122
123123pub fn exit(code: i32) -> noreturn {
124 c.exit(code)
124 c.exit(code);
125125}
126126
127127pub fn isatty(fd: i32) -> bool {
128 c.isatty(fd) != 0
128 return c.isatty(fd) != 0;
129129}
130130
131131pub fn fstat(fd: i32, buf: &c.Stat) -> usize {
132 errnoWrap(c.@"fstat$INODE64"(fd, buf))
132 return errnoWrap(c.@"fstat$INODE64"(fd, buf));
133133}
134134
135135pub 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));
137137}
138138
139139pub 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));
141141}
142142
143143pub fn raise(sig: i32) -> usize {
144 errnoWrap(c.raise(sig))
144 return errnoWrap(c.raise(sig));
145145}
146146
147147pub 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));
149149}
150150
151151pub fn stat(noalias path: &const u8, noalias buf: &stat) -> usize {
152 errnoWrap(c.stat(path, buf))
152 return errnoWrap(c.stat(path, buf));
153153}
154154
155155pub 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));
157157}
158158
159159pub 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,
166166}
167167
168168pub 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));
170170}
171171
172172pub fn unlink(path: &const u8) -> usize {
173 errnoWrap(c.unlink(path))
173 return errnoWrap(c.unlink(path));
174174}
175175
176176pub fn getcwd(buf: &u8, size: usize) -> usize {
177 if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0
177 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0;
178178}
179179
180180pub fn waitpid(pid: i32, status: &i32, options: u32) -> usize {
181181 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)));
183183}
184184
185185pub fn fork() -> usize {
186 errnoWrap(c.fork())
186 return errnoWrap(c.fork());
187187}
188188
189189pub fn pipe(fds: &[2]i32) -> usize {
190190 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)));
192192}
193193
194194pub fn mkdir(path: &const u8, mode: u32) -> usize {
195 errnoWrap(c.mkdir(path, mode))
195 return errnoWrap(c.mkdir(path, mode));
196196}
197197
198198pub fn symlink(existing: &const u8, new: &const u8) -> usize {
199 errnoWrap(c.symlink(existing, new))
199 return errnoWrap(c.symlink(existing, new));
200200}
201201
202202pub fn rename(old: &const u8, new: &const u8) -> usize {
203 errnoWrap(c.rename(old, new))
203 return errnoWrap(c.rename(old, new));
204204}
205205
206206pub fn chdir(path: &const u8) -> usize {
207 errnoWrap(c.chdir(path))
207 return errnoWrap(c.chdir(path));
208208}
209209
210210pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8)
211211 -> usize
212212{
213 errnoWrap(c.execve(path, argv, envp))
213 return errnoWrap(c.execve(path, argv, envp));
214214}
215215
216216pub fn dup2(old: i32, new: i32) -> usize {
217 errnoWrap(c.dup2(old, new))
217 return errnoWrap(c.dup2(old, new));
218218}
219219
220220pub 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));
222222}
223223
224224pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize {
225 errnoWrap(c.nanosleep(req, rem))
225 return errnoWrap(c.nanosleep(req, rem));
226226}
227227
228228pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) -> usize {
229 if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0
229 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0;
230230}
231231
232232pub fn setreuid(ruid: u32, euid: u32) -> usize {
233 errnoWrap(c.setreuid(ruid, euid))
233 return errnoWrap(c.setreuid(ruid, euid));
234234}
235235
236236pub fn setregid(rgid: u32, egid: u32) -> usize {
237 errnoWrap(c.setregid(rgid, egid))
237 return errnoWrap(c.setregid(rgid, egid));
238238}
239239
240240pub 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));
242242}
243243
244244pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {
......@@ -285,9 +285,5 @@ pub fn sigaddset(set: &sigset_t, signo: u5) {
285285/// that the kernel represents it to libc. Errno was a mistake, let's make
286286/// it go away forever.
287287fn errnoWrap(value: isize) -> usize {
288 @bitCast(usize, if (value == -1) {
289 -isize(*c._errno())
290 } else {
291 value
292 })
288 return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);
293289}
std/os/index.zig+163-81
......@@ -84,7 +84,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {
8484 posix.EFAULT => unreachable,
8585 posix.EINTR => continue,
8686 else => unexpectedErrorPosix(err),
87 }
87 };
8888 }
8989 return;
9090 },
......@@ -151,18 +151,17 @@ pub coldcc fn exit(status: i32) -> noreturn {
151151 }
152152 switch (builtin.os) {
153153 Os.linux, Os.darwin, Os.macosx, Os.ios => {
154 posix.exit(status)
154 posix.exit(status);
155155 },
156156 Os.windows => {
157157 // Map a possibly negative status code to a non-negative status for the systems default
158158 // integer width.
159 const p_status = if (@sizeOf(c_uint) < @sizeOf(u32)) {
159 const p_status = if (@sizeOf(c_uint) < @sizeOf(u32))
160160 @truncate(c_uint, @bitCast(u32, status))
161 } else {
162 c_uint(@bitCast(u32, status))
163 };
161 else
162 c_uint(@bitCast(u32, status));
164163
165 windows.ExitProcess(p_status)
164 windows.ExitProcess(p_status);
166165 },
167166 else => @compileError("Unsupported OS"),
168167 }
......@@ -289,7 +288,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al
289288 posix.EPERM => error.AccessDenied,
290289 posix.EEXIST => error.PathAlreadyExists,
291290 else => unexpectedErrorPosix(err),
292 }
291 };
293292 }
294293 return i32(result);
295294 }
......@@ -680,7 +679,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) -> %void
680679 windows.ERROR.ACCESS_DENIED => error.AccessDenied,
681680 windows.ERROR.FILENAME_EXCED_RANGE, windows.ERROR.INVALID_PARAMETER => error.NameTooLong,
682681 else => unexpectedErrorWindows(err),
683 }
682 };
684683 }
685684}
686685
......@@ -902,40 +901,41 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) -> %void {
902901/// this function recursively removes its entries and then tries again.
903902// TODO non-recursive implementation
904903pub fn deleteTree(allocator: &Allocator, full_path: []const u8) -> %void {
905start_over:
906 // First, try deleting the item as a file. This way we don't follow sym links.
907 if (deleteFile(allocator, full_path)) {
908 return;
909 } else |err| {
910 if (err == error.FileNotFound)
904 start_over: while (true) {
905 // First, try deleting the item as a file. This way we don't follow sym links.
906 if (deleteFile(allocator, full_path)) {
911907 return;
912 if (err != error.IsDir)
913 return err;
914 }
915 {
916 var dir = Dir.open(allocator, full_path) %% |err| {
908 } else |err| {
917909 if (err == error.FileNotFound)
918910 return;
919 if (err == error.NotDir)
920 goto start_over;
921 return err;
922 };
923 defer dir.close();
911 if (err != error.IsDir)
912 return err;
913 }
914 {
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);
926 defer full_entry_buf.deinit();
924 var full_entry_buf = ArrayList(u8).init(allocator);
925 defer full_entry_buf.deinit();
927926
928 while (%return dir.next()) |entry| {
929 %return full_entry_buf.resize(full_path.len + entry.name.len + 1);
930 const full_entry_path = full_entry_buf.toSlice();
931 mem.copy(u8, full_entry_path, full_path);
932 full_entry_path[full_path.len] = '/';
933 mem.copy(u8, full_entry_path[full_path.len + 1..], entry.name);
927 while (%return dir.next()) |entry| {
928 %return full_entry_buf.resize(full_path.len + entry.name.len + 1);
929 const full_entry_path = full_entry_buf.toSlice();
930 mem.copy(u8, full_entry_path, full_path);
931 full_entry_path[full_path.len] = '/';
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 }
936936 }
937 return deleteDir(allocator, full_path);
937938 }
938 return deleteDir(allocator, full_path);
939939}
940940
941941pub const Dir = struct {
......@@ -988,58 +988,59 @@ pub const Dir = struct {
988988 /// Memory such as file names referenced in this returned entry becomes invalid
989989 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
990990 pub fn next(self: &Dir) -> %?Entry {
991 start_over:
992 if (self.index >= self.end_index) {
993 if (self.buf.len == 0) {
994 self.buf = %return self.allocator.alloc(u8, page_size);
995 }
991 start_over: while (true) {
992 if (self.index >= self.end_index) {
993 if (self.buf.len == 0) {
994 self.buf = %return self.allocator.alloc(u8, page_size);
995 }
996996
997 while (true) {
998 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
999 const err = linux.getErrno(result);
1000 if (err > 0) {
1001 switch (err) {
1002 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1003 posix.EINVAL => {
1004 self.buf = %return self.allocator.realloc(u8, self.buf, self.buf.len * 2);
1005 continue;
1006 },
1007 else => return unexpectedErrorPosix(err),
1008 };
997 while (true) {
998 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
999 const err = linux.getErrno(result);
1000 if (err > 0) {
1001 switch (err) {
1002 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1003 posix.EINVAL => {
1004 self.buf = %return self.allocator.realloc(u8, self.buf, self.buf.len * 2);
1005 continue;
1006 },
1007 else => return unexpectedErrorPosix(err),
1008 }
1009 }
1010 if (result == 0)
1011 return null;
1012 self.index = 0;
1013 self.end_index = result;
1014 break;
10091015 }
1010 if (result == 0)
1011 return null;
1012 self.index = 0;
1013 self.end_index = result;
1014 break;
10151016 }
1016 }
1017 const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]);
1018 const next_index = self.index + linux_entry.d_reclen;
1019 self.index = next_index;
1017 const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]);
1018 const next_index = self.index + linux_entry.d_reclen;
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 .. entries
1024 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1025 goto start_over;
1026 }
1023 // skip . and .. entries
1024 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1025 continue :start_over;
1026 }
10271027
1028 const type_char = self.buf[next_index - 1];
1029 const entry_kind = switch (type_char) {
1030 posix.DT_BLK => Entry.Kind.BlockDevice,
1031 posix.DT_CHR => Entry.Kind.CharacterDevice,
1032 posix.DT_DIR => Entry.Kind.Directory,
1033 posix.DT_FIFO => Entry.Kind.NamedPipe,
1034 posix.DT_LNK => Entry.Kind.SymLink,
1035 posix.DT_REG => Entry.Kind.File,
1036 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1037 else => Entry.Kind.Unknown,
1038 };
1039 return Entry {
1040 .name = name,
1041 .kind = entry_kind,
1042 };
1028 const type_char = self.buf[next_index - 1];
1029 const entry_kind = switch (type_char) {
1030 posix.DT_BLK => Entry.Kind.BlockDevice,
1031 posix.DT_CHR => Entry.Kind.CharacterDevice,
1032 posix.DT_DIR => Entry.Kind.Directory,
1033 posix.DT_FIFO => Entry.Kind.NamedPipe,
1034 posix.DT_LNK => Entry.Kind.SymLink,
1035 posix.DT_REG => Entry.Kind.File,
1036 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1037 else => Entry.Kind.Unknown,
1038 };
1039 return Entry {
1040 .name = name,
1041 .kind = entry_kind,
1042 };
1043 }
10431044 }
10441045};
10451046
......@@ -1422,6 +1423,54 @@ pub fn args() -> ArgIterator {
14221423 return ArgIterator.init();
14231424}
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
14251474test "windows arg parsing" {
14261475 testWindowsCmdLine(c"a b\tc d", [][]const u8{"a", "b", "c", "d"});
14271476 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{"abc", "d", "e"});
......@@ -1494,6 +1543,39 @@ pub fn openSelfExe() -> %io.File {
14941543 }
14951544}
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
14971579pub fn isTty(handle: FileHandle) -> bool {
14981580 if (is_windows) {
14991581 return windows_util.windowsIsTty(handle);
std/os/linux.zig+68-90
......@@ -367,14 +367,14 @@ pub const TFD_CLOEXEC = O_CLOEXEC;
367367pub const TFD_TIMER_ABSTIME = 1;
368368pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
369369
370fn unsigned(s: i32) -> u32 { @bitCast(u32, s) }
371fn signed(s: u32) -> i32 { @bitCast(i32, s) }
372pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) }
373pub fn WTERMSIG(s: i32) -> i32 { signed(unsigned(s) & 0x7f) }
374pub fn WSTOPSIG(s: i32) -> i32 { WEXITSTATUS(s) }
375pub fn WIFEXITED(s: i32) -> bool { WTERMSIG(s) == 0 }
376pub fn WIFSTOPPED(s: i32) -> bool { (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00 }
377pub fn WIFSIGNALED(s: i32) -> bool { (unsigned(s)&0xffff)-%1 < 0xff }
370fn unsigned(s: i32) -> u32 { return @bitCast(u32, s); }
371fn signed(s: u32) -> i32 { return @bitCast(i32, s); }
372pub fn WEXITSTATUS(s: i32) -> i32 { return signed((unsigned(s) & 0xff00) >> 8); }
373pub fn WTERMSIG(s: i32) -> i32 { return signed(unsigned(s) & 0x7f); }
374pub fn WSTOPSIG(s: i32) -> i32 { return WEXITSTATUS(s); }
375pub fn WIFEXITED(s: i32) -> bool { return WTERMSIG(s) == 0; }
376pub fn WIFSTOPPED(s: i32) -> bool { return (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00; }
377pub fn WIFSIGNALED(s: i32) -> bool { return (unsigned(s)&0xffff)-%1 < 0xff; }
378378
379379
380380pub const winsize = extern struct {
......@@ -387,31 +387,31 @@ pub const winsize = extern struct {
387387/// Get the errno from a syscall return value, or 0 for no error.
388388pub fn getErrno(r: usize) -> usize {
389389 const signed_r = @bitCast(isize, r);
390 if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0
390 return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
391391}
392392
393393pub 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));
395395}
396396
397397pub fn chdir(path: &const u8) -> usize {
398 arch.syscall1(arch.SYS_chdir, @ptrToInt(path))
398 return arch.syscall1(arch.SYS_chdir, @ptrToInt(path));
399399}
400400
401401pub 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));
403403}
404404
405405pub fn fork() -> usize {
406 arch.syscall0(arch.SYS_fork)
406 return arch.syscall0(arch.SYS_fork);
407407}
408408
409409pub 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);
411411}
412412
413413pub 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);
415415}
416416
417417pub fn isatty(fd: i32) -> bool {
......@@ -420,123 +420,123 @@ pub fn isatty(fd: i32) -> bool {
420420}
421421
422422pub 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);
424424}
425425
426426pub 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);
428428}
429429
430430pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize)
431431 -> usize
432432{
433 arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
434 @bitCast(usize, offset))
433 return arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
434 @bitCast(usize, offset));
435435}
436436
437437pub 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);
439439}
440440
441441pub 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);
443443}
444444
445445pub fn rmdir(path: &const u8) -> usize {
446 arch.syscall1(arch.SYS_rmdir, @ptrToInt(path))
446 return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path));
447447}
448448
449449pub 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));
451451}
452452
453453pub 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);
455455}
456456
457457pub fn pipe(fd: &[2]i32) -> usize {
458 pipe2(fd, 0)
458 return pipe2(fd, 0);
459459}
460460
461461pub 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);
463463}
464464
465465pub 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);
467467}
468468
469469pub 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);
471471}
472472
473473pub 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));
475475}
476476
477477pub 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);
479479}
480480
481481pub 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);
483483}
484484
485485pub 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);
487487}
488488
489489pub fn close(fd: i32) -> usize {
490 arch.syscall1(arch.SYS_close, usize(fd))
490 return arch.syscall1(arch.SYS_close, usize(fd));
491491}
492492
493493pub 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);
495495}
496496
497497pub fn exit(status: i32) -> noreturn {
498498 _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status)));
499 unreachable
499 unreachable;
500500}
501501
502502pub 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));
504504}
505505
506506pub 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));
508508}
509509
510510pub fn unlink(path: &const u8) -> usize {
511 arch.syscall1(arch.SYS_unlink, @ptrToInt(path))
511 return arch.syscall1(arch.SYS_unlink, @ptrToInt(path));
512512}
513513
514514pub 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);
516516}
517517
518518pub 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));
520520}
521521
522522pub fn setuid(uid: u32) -> usize {
523 arch.syscall1(arch.SYS_setuid, uid)
523 return arch.syscall1(arch.SYS_setuid, uid);
524524}
525525
526526pub fn setgid(gid: u32) -> usize {
527 arch.syscall1(arch.SYS_setgid, gid)
527 return arch.syscall1(arch.SYS_setgid, gid);
528528}
529529
530530pub fn setreuid(ruid: u32, euid: u32) -> usize {
531 arch.syscall2(arch.SYS_setreuid, ruid, euid)
531 return arch.syscall2(arch.SYS_setreuid, ruid, euid);
532532}
533533
534534pub fn setregid(rgid: u32, egid: u32) -> usize {
535 arch.syscall2(arch.SYS_setregid, rgid, egid)
535 return arch.syscall2(arch.SYS_setregid, rgid, egid);
536536}
537537
538538pub 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);
540540}
541541
542542pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {
......@@ -651,92 +651,70 @@ pub const iovec = extern struct {
651651 iov_len: usize,
652652};
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
676654pub 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));
678656}
679657
680658pub 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));
682660}
683661
684662pub 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));
686664}
687665
688666pub 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));
690668}
691669
692670pub 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));
694672}
695673
696674pub 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);
698676}
699677
700678pub 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));
702680}
703681
704682pub 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);
706684}
707685
708686pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
709687 noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize
710688{
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));
712690}
713691
714692pub 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));
716694}
717695
718696pub 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));
720698}
721699
722700pub 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));
724702}
725703
726704pub 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));
728706}
729707
730708pub 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]));
732710}
733711
734712pub 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);
736714}
737715
738716pub 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);
740718}
741719
742720// error NameTooLong;
......@@ -771,7 +749,7 @@ pub const Stat = arch.Stat;
771749pub const timespec = arch.timespec;
772750
773751pub 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));
775753}
776754
777755pub const epoll_data = u64;
......@@ -782,19 +760,19 @@ pub const epoll_event = extern struct {
782760};
783761
784762pub fn epoll_create() -> usize {
785 arch.syscall1(arch.SYS_epoll_create, usize(1))
763 return arch.syscall1(arch.SYS_epoll_create, usize(1));
786764}
787765
788766pub 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));
790768}
791769
792770pub 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));
794772}
795773
796774pub 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));
798776}
799777
800778pub const itimerspec = extern struct {
......@@ -803,11 +781,11 @@ pub const itimerspec = extern struct {
803781};
804782
805783pub 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));
807785}
808786
809787pub 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));
811789}
812790
813791test "import linux_test" {
std/os/linux_i386.zig-10
......@@ -502,13 +502,3 @@ pub nakedcc fn restore_rt() {
502502 : [number] "{eax}" (usize(SYS_rt_sigreturn))
503503 : "rcx", "r11")
504504}
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;
371371pub const F_GETOWNER_UIDS = 17;
372372
373373pub fn syscall0(number: usize) -> usize {
374 asm volatile ("syscall"
374 return asm volatile ("syscall"
375375 : [ret] "={rax}" (-> usize)
376376 : [number] "{rax}" (number)
377 : "rcx", "r11")
377 : "rcx", "r11");
378378}
379379
380380pub fn syscall1(number: usize, arg1: usize) -> usize {
381 asm volatile ("syscall"
381 return asm volatile ("syscall"
382382 : [ret] "={rax}" (-> usize)
383383 : [number] "{rax}" (number),
384384 [arg1] "{rdi}" (arg1)
385 : "rcx", "r11")
385 : "rcx", "r11");
386386}
387387
388388pub fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize {
389 asm volatile ("syscall"
389 return asm volatile ("syscall"
390390 : [ret] "={rax}" (-> usize)
391391 : [number] "{rax}" (number),
392392 [arg1] "{rdi}" (arg1),
393393 [arg2] "{rsi}" (arg2)
394 : "rcx", "r11")
394 : "rcx", "r11");
395395}
396396
397397pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
398 asm volatile ("syscall"
398 return asm volatile ("syscall"
399399 : [ret] "={rax}" (-> usize)
400400 : [number] "{rax}" (number),
401401 [arg1] "{rdi}" (arg1),
402402 [arg2] "{rsi}" (arg2),
403403 [arg3] "{rdx}" (arg3)
404 : "rcx", "r11")
404 : "rcx", "r11");
405405}
406406
407407pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize {
408 asm volatile ("syscall"
408 return asm volatile ("syscall"
409409 : [ret] "={rax}" (-> usize)
410410 : [number] "{rax}" (number),
411411 [arg1] "{rdi}" (arg1),
412412 [arg2] "{rsi}" (arg2),
413413 [arg3] "{rdx}" (arg3),
414414 [arg4] "{r10}" (arg4)
415 : "rcx", "r11")
415 : "rcx", "r11");
416416}
417417
418418pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize {
419 asm volatile ("syscall"
419 return asm volatile ("syscall"
420420 : [ret] "={rax}" (-> usize)
421421 : [number] "{rax}" (number),
422422 [arg1] "{rdi}" (arg1),
......@@ -424,13 +424,13 @@ pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz
424424 [arg3] "{rdx}" (arg3),
425425 [arg4] "{r10}" (arg4),
426426 [arg5] "{r8}" (arg5)
427 : "rcx", "r11")
427 : "rcx", "r11");
428428}
429429
430430pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
431431 arg5: usize, arg6: usize) -> usize
432432{
433 asm volatile ("syscall"
433 return asm volatile ("syscall"
434434 : [ret] "={rax}" (-> usize)
435435 : [number] "{rax}" (number),
436436 [arg1] "{rdi}" (arg1),
......@@ -439,14 +439,14 @@ pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz
439439 [arg4] "{r10}" (arg4),
440440 [arg5] "{r8}" (arg5),
441441 [arg6] "{r9}" (arg6)
442 : "rcx", "r11")
442 : "rcx", "r11");
443443}
444444
445445pub nakedcc fn restore_rt() {
446 asm volatile ("syscall"
446 return asm volatile ("syscall"
447447 :
448448 : [number] "{rax}" (usize(SYS_rt_sigreturn))
449 : "rcx", "r11")
449 : "rcx", "r11");
450450}
451451
452452
std/os/path.zig+19-19
......@@ -749,21 +749,19 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8)
749749 const resolved_to = %return resolveWindows(allocator, [][]const u8{to});
750750 defer if (clean_up_resolved_to) allocator.free(resolved_to);
751751
752 const result_is_to = if (drive(resolved_to)) |to_drive| {
753 if (drive(resolved_from)) |from_drive| {
752 const result_is_to = if (drive(resolved_to)) |to_drive|
753 if (drive(resolved_from)) |from_drive|
754754 asciiUpper(from_drive[0]) != asciiUpper(to_drive[0])
755 } else {
755 else
756756 true
757 }
758 } else if (networkShare(resolved_to)) |to_ns| {
759 if (networkShare(resolved_from)) |from_ns| {
757 else if (networkShare(resolved_to)) |to_ns|
758 if (networkShare(resolved_from)) |from_ns|
760759 !networkShareServersEql(to_ns, from_ns)
761 } else {
760 else
762761 true
763 }
764 } else {
765 unreachable
766 };
762 else
763 unreachable;
764
767765 if (result_is_to) {
768766 clean_up_resolved_to = false;
769767 return resolved_to;
......@@ -964,14 +962,16 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
964962
965963 // windows returns \\?\ prepended to the path
966964 // we strip it because nobody wants \\?\ prepended to their path
967 const final_len = if (result > 4 and mem.startsWith(u8, buf, "\\\\?\\")) {
968 var i: usize = 4;
969 while (i < result) : (i += 1) {
970 buf[i - 4] = buf[i];
965 const final_len = x: {
966 if (result > 4 and mem.startsWith(u8, buf, "\\\\?\\")) {
967 var i: usize = 4;
968 while (i < result) : (i += 1) {
969 buf[i - 4] = buf[i];
970 }
971 break :x result - 4;
972 } else {
973 break :x result;
971974 }
972 result - 4
973 } else {
974 result
975975 };
976976
977977 return allocator.shrink(u8, buf, final_len);
......@@ -1012,7 +1012,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
10121012 defer os.close(fd);
10131013
10141014 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
10171017 return os.readLink(allocator, proc_path);
10181018 },
std/os/windows/util.zig+5-5
......@@ -16,11 +16,11 @@ pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) ->
1616 windows.WAIT_ABANDONED => error.WaitAbandoned,
1717 windows.WAIT_OBJECT_0 => {},
1818 windows.WAIT_TIMEOUT => error.WaitTimeOut,
19 windows.WAIT_FAILED => {
19 windows.WAIT_FAILED => x: {
2020 const err = windows.GetLastError();
21 switch (err) {
21 break :x switch (err) {
2222 else => os.unexpectedErrorWindows(err),
23 }
23 };
2424 },
2525 else => error.Unexpected,
2626 };
......@@ -122,7 +122,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
122122/// Caller must free result.
123123pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 {
124124 // count bytes needed
125 const bytes_needed = {
125 const bytes_needed = x: {
126126 var bytes_needed: usize = 1; // 1 for the final null byte
127127 var it = env_map.iterator();
128128 while (it.next()) |pair| {
......@@ -130,7 +130,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap)
130130 // +1 for null byte
131131 bytes_needed += pair.key.len + pair.value.len + 2;
132132 }
133 bytes_needed
133 break :x bytes_needed;
134134 };
135135 const result = %return allocator.alloc(u8, bytes_needed);
136136 %defer allocator.free(result);
std/rand.zig+14-14
......@@ -28,9 +28,9 @@ pub const Rand = struct {
2828
2929 /// Initialize random state with the given seed.
3030 pub fn init(seed: usize) -> Rand {
31 Rand {
31 return Rand {
3232 .rng = Rng.init(seed),
33 }
33 };
3434 }
3535
3636 /// Get an integer or boolean with random bits.
......@@ -78,13 +78,13 @@ pub const Rand = struct {
7878 const end_uint = uint(end);
7979 const total_range = math.absCast(start) + end_uint;
8080 const value = r.range(uint, 0, total_range);
81 const result = if (value < end_uint) {
82 T(value)
83 } else if (value == end_uint) {
84 start
85 } else {
81 const result = if (value < end_uint) x: {
82 break :x T(value);
83 } else if (value == end_uint) x: {
84 break :x start;
85 } else x: {
8686 // Can't overflow because the range is over signed ints
87 %%math.negateCast(value - end_uint)
87 break :x %%math.negateCast(value - end_uint);
8888 };
8989 return result;
9090 } else {
......@@ -114,13 +114,13 @@ pub const Rand = struct {
114114 // const rand_bits = r.rng.scalar(int) & mask;
115115 // return @float_compose(T, false, 0, rand_bits) - 1.0
116116 const int_type = @IntType(false, @sizeOf(T) * 8);
117 const precision = if (T == f32) {
117 const precision = if (T == f32)
118118 16777216
119 } else if (T == f64) {
119 else if (T == f64)
120120 9007199254740992
121 } else {
121 else
122122 @compileError("unknown floating point type")
123 };
123 ;
124124 return T(r.range(int_type, 0, precision)) / T(precision);
125125 }
126126};
......@@ -133,7 +133,7 @@ fn MersenneTwister(
133133 comptime t: math.Log2Int(int), comptime c: int,
134134 comptime l: math.Log2Int(int), comptime f: int) -> type
135135{
136 struct {
136 return struct {
137137 const Self = this;
138138
139139 array: [n]int,
......@@ -189,7 +189,7 @@ fn MersenneTwister(
189189
190190 return x;
191191 }
192 }
192 };
193193}
194194
195195test "rand float 32" {
std/sort.zig+1022-50
......@@ -1,75 +1,966 @@
1const assert = @import("debug.zig").assert;
2const mem = @import("mem.zig");
3const math = @import("math/index.zig");
1const std = @import("index.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const math = std.math;
5const builtin = @import("builtin");
46
5pub const Cmp = math.Cmp;
6
7/// Stable sort using O(1) space. Currently implemented as insertion sort.
8pub fn sort_stable(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) {
9 {var i: usize = 1; while (i < array.len) : (i += 1) {
10 const x = array[i];
7/// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required).
8pub fn insertionSort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)->bool) {
9 {var i: usize = 1; while (i < items.len) : (i += 1) {
10 const x = items[i];
1111 var j: usize = i;
12 while (j > 0 and cmp(array[j - 1], x) == Cmp.Greater) : (j -= 1) {
13 array[j] = array[j - 1];
12 while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) {
13 items[j] = items[j - 1];
1414 }
15 array[j] = x;
15 items[j] = x;
1616 }}
1717}
1818
19/// Unstable sort using O(n) stack space. Currently implemented as quicksort.
20pub fn sort(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) {
21 if (array.len > 0) {
22 quicksort(T, array, 0, array.len - 1, cmp);
19const Range = struct {
20 start: usize,
21 end: usize,
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;
23708 }
24709}
25710
26fn quicksort(comptime T: type, array: []T, left: usize, right: usize, comptime cmp: fn(a: &const T, b: &const T)->Cmp) {
27 var i = left;
28 var j = right;
29 const p = (i + j) / 2;
711// merge operation without a buffer
712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)->bool) {
713 if (A_arg.length() == 0 or B_arg.length() == 0) return;
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) {
32 while (cmp(array[i], array[p]) == Cmp.Less) {
33 i += 1;
733 var A = *A_arg;
734 var B = *B_arg;
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 }
34774 }
35 while (cmp(array[j], array[p]) == Cmp.Greater) {
36 j -= 1;
775 }
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);
37798 }
38 if (i <= j) {
39 const tmp = array[i];
40 array[i] = array[j];
41 array[j] = tmp;
42 i += 1;
43 if (j > 0) j -= 1;
799 }
800
801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);
802}
803
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);
44812 }
45813 }
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);
48 if (i < right) quicksort(T, array, i, right, cmp);
818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool, unique: usize) -> usize {
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);
49830}
50831
51pub fn i32asc(a: &const i32, b: &const i32) -> Cmp {
52 return if (*a > *b) Cmp.Greater else if (*a < *b) Cmp.Less else Cmp.Equal
832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool, unique: usize) -> usize {
833 if (range.length() == 0) return range.start;
834 const skip = math.max(range.length()/unique, usize(1));
835
836 var index = range.end - skip;
837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {
838 if (index < range.start + skip) {
839 return binaryLast(T, items, value, Range.init(range.start, index), lessThan);
840 }
841 }
842
843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);
53844}
54845
55pub fn i32desc(a: &const i32, b: &const i32) -> Cmp {
56 reverse(i32asc(a, b))
846fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool) -> usize {
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;
57862}
58863
59pub fn u8asc(a: &const u8, b: &const u8) -> Cmp {
60 if (*a > *b) Cmp.Greater else if (*a < *b) Cmp.Less else Cmp.Equal
864fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)->bool) -> usize {
865 var start = range.start;
866 var end = range.end - 1;
867 if (range.start >= range.end) return range.end;
868 while (start < end) {
869 const mid = start + (end - start)/2;
870 if (!lessThan(value, items[mid])) {
871 start = mid + 1;
872 } else {
873 end = mid;
874 }
875 }
876 if (start == range.end - 1 and !lessThan(value, items[start])) {
877 start += 1;
878 }
879 return start;
61880}
62881
63pub fn u8desc(a: &const u8, b: &const u8) -> Cmp {
64 reverse(u8asc(a, b))
882fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)->bool, into: []T) {
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 }
65910}
66911
67fn reverse(was: Cmp) -> Cmp {
68 if (was == Cmp.Greater) Cmp.Less else if (was == Cmp.Less) Cmp.Greater else Cmp.Equal
912fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)->bool, cache: []T) {
913 // A fits into the cache, so use that instead of the internal buffer
914 var A_index: usize = 0;
915 var B_index: usize = B.start;
916 var insert_index: usize = A.start;
917 const A_last = A.length();
918 const B_last = B.end;
919
920 if (B.length() > 0 and A.length() > 0) {
921 while (true) {
922 if (!lessThan(items[B_index], cache[A_index])) {
923 items[insert_index] = cache[A_index];
924 A_index += 1;
925 insert_index += 1;
926 if (A_index == A_last) break;
927 } else {
928 items[insert_index] = items[B_index];
929 B_index += 1;
930 insert_index += 1;
931 if (B_index == B_last) break;
932 }
933 }
934 }
935
936 // copy the remainder of A into the final array
937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);
938}
939
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;
69951}
70952
71// ---------------------------------------
72// tests
953fn i32desc(lhs: &const i32, rhs: &const i32) -> bool {
954 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
74965test "stable sort" {
75966 testStableSort();
......@@ -113,7 +1004,7 @@ fn testStableSort() {
1131004 },
1141005 };
1151006 for (cases) |*case| {
116 sort_stable(IdAndValue, (*case)[0..], cmpByValue);
1007 insertionSort(IdAndValue, (*case)[0..], cmpByValue);
1171008 for (*case) |item, i| {
1181009 assert(item.id == expected[i].id);
1191010 assert(item.value == expected[i].value);
......@@ -121,14 +1012,19 @@ fn testStableSort() {
1211012 }
1221013}
1231014const IdAndValue = struct {
124 id: i32,
1015 id: usize,
1251016 value: i32,
1261017};
127fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> Cmp {
1018fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> bool {
1281019 return i32asc(a.value, b.value);
1291020}
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 }
1321028 const u8cases = [][]const []const u8 {
1331029 [][]const u8{"", ""},
1341030 [][]const u8{"a", "a"},
......@@ -164,7 +1060,12 @@ test "testSort" {
1641060 }
1651061}
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 }
1681069 const rev_cases = [][]const []const i32 {
1691070 [][]const i32{[]i32{}, []i32{}},
1701071 [][]const i32{[]i32{1}, []i32{1}},
......@@ -182,3 +1083,74 @@ test "testSortDesc" {
1821083 assert(mem.eql(i32, slice, case[1]));
1831084 }
1841085}
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");
55const std = @import("std");
66const 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
138var argc_ptr: &usize = undefined;
149
15
16export nakedcc fn _start() -> noreturn {
17 if (!want_start_symbol) {
18 @setGlobalLinkage(_start, builtin.GlobalLinkage.Internal);
19 unreachable;
10comptime {
11 const strong_linkage = builtin.GlobalLinkage.Strong;
12 if (builtin.link_libc) {
13 @export("main", main, strong_linkage);
14 } else if (builtin.os == builtin.Os.windows) {
15 @export("WinMainCRTStartup", WinMainCRTStartup, strong_linkage);
16 } else {
17 @export("_start", _start, strong_linkage);
2018 }
19}
2120
21nakedcc fn _start() -> noreturn {
2222 switch (builtin.arch) {
2323 builtin.Arch.x86_64 => {
2424 argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize));
......@@ -28,17 +28,14 @@ export nakedcc fn _start() -> noreturn {
2828 },
2929 else => @compileError("unsupported arch"),
3030 }
31 posixCallMainAndExit()
31 // If LLVM inlines stack variables into _start, they will overwrite
32 // the command line argument data.
33 @noInlineCall(posixCallMainAndExit);
3234}
3335
34export fn WinMainCRTStartup() -> noreturn {
35 if (!want_WinMainCRTStartup) {
36 @setGlobalLinkage(WinMainCRTStartup, builtin.GlobalLinkage.Internal);
37 unreachable;
38 }
36extern fn WinMainCRTStartup() -> noreturn {
3937 @setAlignStack(16);
4038
41 std.debug.user_main_fn = root.main;
4239 root.main() %% std.os.windows.ExitProcess(1);
4340 std.os.windows.ExitProcess(0);
4441}
......@@ -58,17 +55,10 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
5855 while (envp[env_count] != null) : (env_count += 1) {}
5956 std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];
6057
61 std.debug.user_main_fn = root.main;
62
6358 return root.main();
6459}
6560
66export 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
61extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
7262 callMain(usize(c_argc), c_argv, c_envp) %% return 1;
7363 return 0;
7464}
std/special/bootstrap_lib.zig+5-1
......@@ -2,7 +2,11 @@
22
33const 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,
610 lpReserved: std.os.windows.LPVOID) -> std.os.windows.BOOL
711{
812 return std.os.windows.TRUE;
std/special/build_runner.zig+6-10
......@@ -45,21 +45,17 @@ pub fn main() -> %void {
4545
4646 var stderr_file = io.getStdErr();
4747 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: {
4949 stderr_file_stream = io.FileOutStream.init(f);
50 &stderr_file_stream.stream
51 } else |err| {
52 err
53 };
50 break :x &stderr_file_stream.stream;
51 } else |err| err;
5452
5553 var stdout_file = io.getStdOut();
5654 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: {
5856 stdout_file_stream = io.FileOutStream.init(f);
59 &stdout_file_stream.stream
60 } else |err| {
61 err
62 };
57 break :x &stdout_file_stream.stream;
58 } else |err| err;
6359
6460 while (arg_it.next(allocator)) |err_or_arg| {
6561 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) {
3535 (??dest)[index] = (??src)[index];
3636}
3737
38export fn __stack_chk_fail() -> noreturn {
39 if (builtin.mode == builtin.Mode.ReleaseFast or builtin.os == builtin.Os.windows) {
40 @setGlobalLinkage(__stack_chk_fail, builtin.GlobalLinkage.Internal);
41 unreachable;
38comptime {
39 if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) {
40 @export("__stack_chk_fail", __stack_chk_fail, builtin.GlobalLinkage.Strong);
4241 }
42}
43extern fn __stack_chk_fail() -> noreturn {
4344 @panic("stack smashing detected");
4445}
4546
4647const math = @import("../math/index.zig");
4748
48export fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) }
49export fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) }
49export fn fmodf(x: f32, y: f32) -> f32 { return generic_fmod(f32, x, y); }
50export fn fmod(x: f64, y: f64) -> f64 { return generic_fmod(f64, x, y); }
5051
5152// TODO add intrinsics for these (and probably the double version too)
5253// and have the math stuff use the intrinsic. same as @mod and @rem
53export fn floorf(x: f32) -> f32 { math.floor(x) }
54export fn ceilf(x: f32) -> f32 { math.ceil(x) }
55export fn floor(x: f64) -> f64 { math.floor(x) }
56export fn ceil(x: f64) -> f64 { math.ceil(x) }
54export fn floorf(x: f32) -> f32 { return math.floor(x); }
55export fn ceilf(x: f32) -> f32 { return math.ceil(x); }
56export fn floor(x: f64) -> f64 { return math.floor(x); }
57export fn ceil(x: f64) -> f64 { return math.ceil(x); }
5758
5859fn generic_fmod(comptime T: type, x: T, y: T) -> T {
5960 @setDebugSafety(this, false);
......@@ -83,7 +84,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
8384 // normalize x and y
8485 if (ex == 0) {
8586 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;}) {}
8788 ux <<= log2uint(@bitCast(u32, -ex + 1));
8889 } else {
8990 ux &= @maxValue(uint) >> exp_bits;
......@@ -91,7 +92,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
9192 }
9293 if (ey == 0) {
9394 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;}) {}
9596 uy <<= log2uint(@bitCast(u32, -ey + 1));
9697 } else {
9798 uy &= @maxValue(uint) >> exp_bits;
......@@ -114,7 +115,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
114115 return 0 * x;
115116 ux = i;
116117 }
117 while (ux >> digits == 0) : ({ux <<= 1; ex -= 1}) {}
118 while (ux >> digits == 0) : (b: {ux <<= 1; break :b ex -= 1;}) {}
118119
119120 // scale result up
120121 if (ex > 0) {
std/special/compiler_rt/aulldiv.zig+54-65
......@@ -1,66 +1,55 @@
1const builtin = @import("builtin");
2const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;
3const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386;
4
5export nakedcc fn _aulldiv() {
6 if (is_win32) {
7 @setDebugSafety(this, false);
8 @setGlobalLinkage(_aulldiv, linkage);
9 asm volatile (
10 \\.intel_syntax noprefix
11 \\
12 \\ push ebx
13 \\ push esi
14 \\ mov eax,dword ptr [esp+18h]
15 \\ or eax,eax
16 \\ jne L1
17 \\ mov ecx,dword ptr [esp+14h]
18 \\ mov eax,dword ptr [esp+10h]
19 \\ xor edx,edx
20 \\ div ecx
21 \\ mov ebx,eax
22 \\ mov eax,dword ptr [esp+0Ch]
23 \\ div ecx
24 \\ mov edx,ebx
25 \\ jmp L2
26 \\ L1:
27 \\ mov ecx,eax
28 \\ mov ebx,dword ptr [esp+14h]
29 \\ mov edx,dword ptr [esp+10h]
30 \\ mov eax,dword ptr [esp+0Ch]
31 \\ L3:
32 \\ shr ecx,1
33 \\ rcr ebx,1
34 \\ shr edx,1
35 \\ rcr eax,1
36 \\ or ecx,ecx
37 \\ jne L3
38 \\ div ebx
39 \\ mov esi,eax
40 \\ mul dword ptr [esp+18h]
41 \\ mov ecx,eax
42 \\ mov eax,dword ptr [esp+14h]
43 \\ mul esi
44 \\ add edx,ecx
45 \\ jb L4
46 \\ cmp edx,dword ptr [esp+10h]
47 \\ ja L4
48 \\ jb L5
49 \\ cmp eax,dword ptr [esp+0Ch]
50 \\ jbe L5
51 \\ L4:
52 \\ dec esi
53 \\ L5:
54 \\ xor edx,edx
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;
1pub nakedcc fn _aulldiv() {
2 @setDebugSafety(this, false);
3 asm volatile (
4 \\.intel_syntax noprefix
5 \\
6 \\ push ebx
7 \\ push esi
8 \\ mov eax,dword ptr [esp+18h]
9 \\ or eax,eax
10 \\ jne L1
11 \\ mov ecx,dword ptr [esp+14h]
12 \\ mov eax,dword ptr [esp+10h]
13 \\ xor edx,edx
14 \\ div ecx
15 \\ mov ebx,eax
16 \\ mov eax,dword ptr [esp+0Ch]
17 \\ div ecx
18 \\ mov edx,ebx
19 \\ jmp L2
20 \\ L1:
21 \\ mov ecx,eax
22 \\ mov ebx,dword ptr [esp+14h]
23 \\ mov edx,dword ptr [esp+10h]
24 \\ mov eax,dword ptr [esp+0Ch]
25 \\ L3:
26 \\ shr ecx,1
27 \\ rcr ebx,1
28 \\ shr edx,1
29 \\ rcr eax,1
30 \\ or ecx,ecx
31 \\ jne L3
32 \\ div ebx
33 \\ mov esi,eax
34 \\ mul dword ptr [esp+18h]
35 \\ mov ecx,eax
36 \\ mov eax,dword ptr [esp+14h]
37 \\ mul esi
38 \\ add edx,ecx
39 \\ jb L4
40 \\ cmp edx,dword ptr [esp+10h]
41 \\ ja L4
42 \\ jb L5
43 \\ cmp eax,dword ptr [esp+0Ch]
44 \\ jbe L5
45 \\ L4:
46 \\ dec esi
47 \\ L5:
48 \\ xor edx,edx
49 \\ mov eax,esi
50 \\ L2:
51 \\ pop esi
52 \\ pop ebx
53 \\ ret 10h
54 );
6655}
std/special/compiler_rt/aullrem.zig+55-66
......@@ -1,67 +1,56 @@
1const builtin = @import("builtin");
2const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;
3const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386;
4
5export nakedcc fn _aullrem() {
6 if (is_win32) {
7 @setDebugSafety(this, false);
8 @setGlobalLinkage(_aullrem, linkage);
9 asm volatile (
10 \\.intel_syntax noprefix
11 \\
12 \\ push ebx
13 \\ mov eax,dword ptr [esp+14h]
14 \\ or eax,eax
15 \\ jne L1a
16 \\ mov ecx,dword ptr [esp+10h]
17 \\ mov eax,dword ptr [esp+0Ch]
18 \\ xor edx,edx
19 \\ div ecx
20 \\ mov eax,dword ptr [esp+8]
21 \\ div ecx
22 \\ mov eax,edx
23 \\ xor edx,edx
24 \\ jmp L2a
25 \\ L1a:
26 \\ mov ecx,eax
27 \\ mov ebx,dword ptr [esp+10h]
28 \\ mov edx,dword ptr [esp+0Ch]
29 \\ mov eax,dword ptr [esp+8]
30 \\ L3a:
31 \\ shr ecx,1
32 \\ rcr ebx,1
33 \\ shr edx,1
34 \\ rcr eax,1
35 \\ or ecx,ecx
36 \\ jne L3a
37 \\ div ebx
38 \\ mov ecx,eax
39 \\ mul dword ptr [esp+14h]
40 \\ xchg eax,ecx
41 \\ mul dword ptr [esp+10h]
42 \\ add edx,ecx
43 \\ jb L4a
44 \\ cmp edx,dword ptr [esp+0Ch]
45 \\ ja L4a
46 \\ jb L5a
47 \\ cmp eax,dword ptr [esp+8]
48 \\ jbe L5a
49 \\ L4a:
50 \\ sub eax,dword ptr [esp+10h]
51 \\ sbb edx,dword ptr [esp+14h]
52 \\ L5a:
53 \\ sub eax,dword ptr [esp+8]
54 \\ sbb edx,dword ptr [esp+0Ch]
55 \\ neg edx
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;
1pub nakedcc fn _aullrem() {
2 @setDebugSafety(this, false);
3 asm volatile (
4 \\.intel_syntax noprefix
5 \\
6 \\ push ebx
7 \\ mov eax,dword ptr [esp+14h]
8 \\ or eax,eax
9 \\ jne L1a
10 \\ mov ecx,dword ptr [esp+10h]
11 \\ mov eax,dword ptr [esp+0Ch]
12 \\ xor edx,edx
13 \\ div ecx
14 \\ mov eax,dword ptr [esp+8]
15 \\ div ecx
16 \\ mov eax,edx
17 \\ xor edx,edx
18 \\ jmp L2a
19 \\ L1a:
20 \\ mov ecx,eax
21 \\ mov ebx,dword ptr [esp+10h]
22 \\ mov edx,dword ptr [esp+0Ch]
23 \\ mov eax,dword ptr [esp+8]
24 \\ L3a:
25 \\ shr ecx,1
26 \\ rcr ebx,1
27 \\ shr edx,1
28 \\ rcr eax,1
29 \\ or ecx,ecx
30 \\ jne L3a
31 \\ div ebx
32 \\ mov ecx,eax
33 \\ mul dword ptr [esp+14h]
34 \\ xchg eax,ecx
35 \\ mul dword ptr [esp+10h]
36 \\ add edx,ecx
37 \\ jb L4a
38 \\ cmp edx,dword ptr [esp+0Ch]
39 \\ ja L4a
40 \\ jb L5a
41 \\ cmp eax,dword ptr [esp+8]
42 \\ jbe L5a
43 \\ L4a:
44 \\ sub eax,dword ptr [esp+10h]
45 \\ sbb edx,dword ptr [esp+14h]
46 \\ L5a:
47 \\ sub eax,dword ptr [esp+8]
48 \\ sbb edx,dword ptr [esp+0Ch]
49 \\ neg edx
50 \\ neg eax
51 \\ sbb edx,0
52 \\ L2a:
53 \\ pop ebx
54 \\ ret 10h
55 );
6756}
std/special/compiler_rt/comparetf2.zig+21-64
......@@ -20,11 +20,9 @@ const infRep = exponentMask;
2020
2121const builtin = @import("builtin");
2222const 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 {
2625 @setDebugSafety(this, is_test);
27 @setGlobalLinkage(__letf2, linkage);
2826
2927 const aInt = @bitCast(rep_t, a);
3028 const bInt = @bitCast(rep_t, b);
......@@ -40,35 +38,25 @@ export fn __letf2(a: f128, b: f128) -> c_int {
4038
4139 // If at least one of a and b is positive, we get the same result comparing
4240 // a and b as signed integers as we would with a floating-point compare.
43 return if ((aInt & bInt) >= 0) {
44 if (aInt < bInt) {
41 return if ((aInt & bInt) >= 0)
42 if (aInt < bInt)
4543 LE_LESS
46 } else if (aInt == bInt) {
44 else if (aInt == bInt)
4745 LE_EQUAL
48 } else {
46 else
4947 LE_GREATER
50 }
51 } else {
48 else
5249 // Otherwise, both are negative, so we need to flip the sense of the
5350 // comparison to get the correct result. (This assumes a twos- or ones-
5451 // complement integer representation; if integers are represented in a
5552 // sign-magnitude representation, then this flip is incorrect).
56 if (aInt > bInt) {
53 if (aInt > bInt)
5754 LE_LESS
58 } else if (aInt == bInt) {
55 else if (aInt == bInt)
5956 LE_EQUAL
60 } else {
57 else
6158 LE_GREATER
62 }
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);
59 ;
7260}
7361
7462// TODO https://github.com/zig-lang/zig/issues/305
......@@ -78,8 +66,7 @@ const GE_EQUAL = c_int(0);
7866const GE_GREATER = c_int(1);
7967const GE_UNORDERED = c_int(-1); // Note: different from LE_UNORDERED
8068
81export fn __getf2(a: f128, b: f128) -> c_int {
82 @setGlobalLinkage(__getf2, linkage);
69pub extern fn __getf2(a: f128, b: f128) -> c_int {
8370 @setDebugSafety(this, is_test);
8471
8572 const aInt = @bitCast(srep_t, a);
......@@ -89,57 +76,27 @@ export fn __getf2(a: f128, b: f128) -> c_int {
8976
9077 if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
9178 if ((aAbs | bAbs) == 0) return GE_EQUAL;
92 return if ((aInt & bInt) >= 0) {
93 if (aInt < bInt) {
79 return if ((aInt & bInt) >= 0)
80 if (aInt < bInt)
9481 GE_LESS
95 } else if (aInt == bInt) {
82 else if (aInt == bInt)
9683 GE_EQUAL
97 } else {
84 else
9885 GE_GREATER
99 }
100 } else {
101 if (aInt > bInt) {
86 else
87 if (aInt > bInt)
10288 GE_LESS
103 } else if (aInt == bInt) {
89 else if (aInt == bInt)
10490 GE_EQUAL
105 } else {
91 else
10692 GE_GREATER
107 }
108 };
93 ;
10994}
11095
111export fn __unordtf2(a: f128, b: f128) -> c_int {
112 @setGlobalLinkage(__unordtf2, linkage);
96pub extern fn __unordtf2(a: f128, b: f128) -> c_int {
11397 @setDebugSafety(this, is_test);
11498
11599 const aAbs = @bitCast(rep_t, a) & absMask;
116100 const bAbs = @bitCast(rep_t, b) & absMask;
117101 return c_int(aAbs > infRep or bAbs > infRep);
118102}
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 @@
11const fixuint = @import("fixuint.zig").fixuint;
22const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunsdfdi(a: f64) -> u64 {
4pub extern fn __fixunsdfdi(a: f64) -> u64 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__fixunsdfdi, linkage);
86 return fixuint(f64, u64, a);
97}
108
std/special/compiler_rt/fixunsdfsi.zig+1-3
......@@ -1,10 +1,8 @@
11const fixuint = @import("fixuint.zig").fixuint;
22const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunsdfsi(a: f64) -> u32 {
4pub extern fn __fixunsdfsi(a: f64) -> u32 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__fixunsdfsi, linkage);
86 return fixuint(f64, u32, a);
97}
108
std/special/compiler_rt/fixunsdfti.zig+1-3
......@@ -1,10 +1,8 @@
11const fixuint = @import("fixuint.zig").fixuint;
22const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunsdfti(a: f64) -> u128 {
4pub extern fn __fixunsdfti(a: f64) -> u128 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__fixunsdfti, linkage);
86 return fixuint(f64, u128, a);
97}
108
std/special/compiler_rt/fixunssfdi.zig+1-3
......@@ -1,10 +1,8 @@
11const fixuint = @import("fixuint.zig").fixuint;
22const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunssfdi(a: f32) -> u64 {
4pub extern fn __fixunssfdi(a: f32) -> u64 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__fixunssfdi, linkage);
86 return fixuint(f32, u64, a);
97}
108
std/special/compiler_rt/fixunssfsi.zig+1-3
......@@ -1,10 +1,8 @@
11const fixuint = @import("fixuint.zig").fixuint;
22const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunssfsi(a: f32) -> u32 {
4pub extern fn __fixunssfsi(a: f32) -> u32 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__fixunssfsi, linkage);
86 return fixuint(f32, u32, a);
97}
108
std/special/compiler_rt/fixunssfti.zig+1-3
......@@ -1,10 +1,8 @@
11const fixuint = @import("fixuint.zig").fixuint;
22const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunssfti(a: f32) -> u128 {
4pub extern fn __fixunssfti(a: f32) -> u128 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__fixunssfti, linkage);
86 return fixuint(f32, u128, a);
97}
108
std/special/compiler_rt/fixunstfdi.zig+1-3
......@@ -1,10 +1,8 @@
11const fixuint = @import("fixuint.zig").fixuint;
22const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunstfdi(a: f128) -> u64 {
4pub extern fn __fixunstfdi(a: f128) -> u64 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__fixunstfdi, linkage);
86 return fixuint(f128, u64, a);
97}
108
std/special/compiler_rt/fixunstfsi.zig+1-3
......@@ -1,10 +1,8 @@
11const fixuint = @import("fixuint.zig").fixuint;
22const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunstfsi(a: f128) -> u32 {
4pub extern fn __fixunstfsi(a: f128) -> u32 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__fixunstfsi, linkage);
86 return fixuint(f128, u32, a);
97}
108
std/special/compiler_rt/fixunstfti.zig+1-3
......@@ -1,10 +1,8 @@
11const fixuint = @import("fixuint.zig").fixuint;
22const builtin = @import("builtin");
3const linkage = @import("index.zig").linkage;
43
5export fn __fixunstfti(a: f128) -> u128 {
4pub extern fn __fixunstfti(a: f128) -> u128 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__fixunstfti, linkage);
86 return fixuint(f128, u128, a);
97}
108
std/special/compiler_rt/index.zig+165-176
......@@ -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
201const builtin = @import("builtin");
212const 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;
26const win64 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.x86_64;
27const win32_nocrt = win32 and !builtin.link_libc;
28const win64_nocrt = win64 and !builtin.link_libc;
29pub const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
30const strong_linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;
37 @export("__udivti3", @import("udivti3.zig").__udivti3, linkage);
38 @export("__umodti3", @import("umodti3.zig").__umodti3, linkage);
39
40 @export("__udivsi3", __udivsi3, linkage);
41 @export("__udivdi3", __udivdi3, linkage);
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
3273const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
3374
......@@ -41,15 +82,13 @@ pub coldcc fn panic(msg: []const u8) -> noreturn {
4182 }
4283}
4384
44export fn __udivdi3(a: u64, b: u64) -> u64 {
85extern fn __udivdi3(a: u64, b: u64) -> u64 {
4586 @setDebugSafety(this, is_test);
46 @setGlobalLinkage(__udivdi3, linkage);
4787 return __udivmoddi4(a, b, null);
4888}
4989
50export fn __umoddi3(a: u64, b: u64) -> u64 {
90extern fn __umoddi3(a: u64, b: u64) -> u64 {
5191 @setDebugSafety(this, is_test);
52 @setGlobalLinkage(__umoddi3, linkage);
5392
5493 var r: u64 = undefined;
5594 _ = __udivmoddi4(a, b, &r);
......@@ -60,17 +99,11 @@ const AeabiUlDivModResult = extern struct {
6099 quot: u64,
61100 rem: u64,
62101};
63export fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult {
102extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult {
64103 @setDebugSafety(this, is_test);
65 if (comptime isArmArch()) {
66 @setGlobalLinkage(__aeabi_uldivmod, linkage);
67 var result: AeabiUlDivModResult = undefined;
68 result.quot = __udivmoddi4(numerator, denominator, &result.rem);
69 return result;
70 }
71
72 @setGlobalLinkage(__aeabi_uldivmod, builtin.GlobalLinkage.Internal);
73 unreachable;
104 var result: AeabiUlDivModResult = undefined;
105 result.quot = __udivmoddi4(numerator, denominator, &result.rem);
106 return result;
74107}
75108
76109fn isArmArch() -> bool {
......@@ -115,156 +148,124 @@ fn isArmArch() -> bool {
115148 };
116149}
117150
118export nakedcc fn __aeabi_uidivmod() {
151nakedcc fn __aeabi_uidivmod() {
119152 @setDebugSafety(this, false);
120
121 if (comptime isArmArch()) {
122 @setGlobalLinkage(__aeabi_uidivmod, linkage);
123 asm volatile (
124 \\ push { lr }
125 \\ sub sp, sp, #4
126 \\ mov r2, sp
127 \\ bl __udivmodsi4
128 \\ ldr r1, [sp]
129 \\ add sp, sp, #4
130 \\ pop { pc }
131 ::: "r2", "r1");
132 unreachable;
133 }
134
135 @setGlobalLinkage(__aeabi_uidivmod, builtin.GlobalLinkage.Internal);
153 asm volatile (
154 \\ push { lr }
155 \\ sub sp, sp, #4
156 \\ mov r2, sp
157 \\ bl __udivmodsi4
158 \\ ldr r1, [sp]
159 \\ add sp, sp, #4
160 \\ pop { pc }
161 ::: "r2", "r1");
136162}
137163
138164// _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments,
139165// then decrement %esp by %eax. Preserves all registers except %esp and flags.
140166// This routine is windows specific
141167// http://msdn.microsoft.com/en-us/library/ms648426.aspx
142export nakedcc fn _chkstk() align(4) {
168nakedcc fn _chkstk() align(4) {
143169 @setDebugSafety(this, false);
144170
145 if (win32_nocrt) {
146 @setGlobalLinkage(_chkstk, strong_linkage);
147 asm volatile (
148 \\ push %%ecx
149 \\ push %%eax
150 \\ cmp $0x1000,%%eax
151 \\ lea 12(%%esp),%%ecx
152 \\ jb 1f
153 \\ 2:
154 \\ sub $0x1000,%%ecx
155 \\ test %%ecx,(%%ecx)
156 \\ sub $0x1000,%%eax
157 \\ cmp $0x1000,%%eax
158 \\ ja 2b
159 \\ 1:
160 \\ sub %%eax,%%ecx
161 \\ test %%ecx,(%%ecx)
162 \\ pop %%eax
163 \\ pop %%ecx
164 \\ ret
165 );
166 unreachable;
167 }
168
169 @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal);
171 asm volatile (
172 \\ push %%ecx
173 \\ push %%eax
174 \\ cmp $0x1000,%%eax
175 \\ lea 12(%%esp),%%ecx
176 \\ jb 1f
177 \\ 2:
178 \\ sub $0x1000,%%ecx
179 \\ test %%ecx,(%%ecx)
180 \\ sub $0x1000,%%eax
181 \\ cmp $0x1000,%%eax
182 \\ ja 2b
183 \\ 1:
184 \\ sub %%eax,%%ecx
185 \\ test %%ecx,(%%ecx)
186 \\ pop %%eax
187 \\ pop %%ecx
188 \\ ret
189 );
170190}
171191
172export nakedcc fn __chkstk() align(4) {
192nakedcc fn __chkstk() align(4) {
173193 @setDebugSafety(this, false);
174194
175 if (win64_nocrt) {
176 @setGlobalLinkage(__chkstk, strong_linkage);
177 asm volatile (
178 \\ push %%rcx
179 \\ push %%rax
180 \\ cmp $0x1000,%%rax
181 \\ lea 24(%%rsp),%%rcx
182 \\ jb 1f
183 \\2:
184 \\ sub $0x1000,%%rcx
185 \\ test %%rcx,(%%rcx)
186 \\ sub $0x1000,%%rax
187 \\ cmp $0x1000,%%rax
188 \\ ja 2b
189 \\1:
190 \\ sub %%rax,%%rcx
191 \\ test %%rcx,(%%rcx)
192 \\ pop %%rax
193 \\ pop %%rcx
194 \\ ret
195 );
196 unreachable;
197 }
198
199 @setGlobalLinkage(__chkstk, builtin.GlobalLinkage.Internal);
195 asm volatile (
196 \\ push %%rcx
197 \\ push %%rax
198 \\ cmp $0x1000,%%rax
199 \\ lea 24(%%rsp),%%rcx
200 \\ jb 1f
201 \\2:
202 \\ sub $0x1000,%%rcx
203 \\ test %%rcx,(%%rcx)
204 \\ sub $0x1000,%%rax
205 \\ cmp $0x1000,%%rax
206 \\ ja 2b
207 \\1:
208 \\ sub %%rax,%%rcx
209 \\ test %%rcx,(%%rcx)
210 \\ pop %%rax
211 \\ pop %%rcx
212 \\ ret
213 );
200214}
201215
202216// _chkstk routine
203217// This routine is windows specific
204218// http://msdn.microsoft.com/en-us/library/ms648426.aspx
205export nakedcc fn __chkstk_ms() align(4) {
219nakedcc fn __chkstk_ms() align(4) {
206220 @setDebugSafety(this, false);
207221
208 if (win32_nocrt) {
209 @setGlobalLinkage(__chkstk_ms, linkage);
210 asm volatile (
211 \\ push %%ecx
212 \\ push %%eax
213 \\ cmp $0x1000,%%eax
214 \\ lea 12(%%esp),%%ecx
215 \\ jb 1f
216 \\ 2:
217 \\ sub $0x1000,%%ecx
218 \\ test %%ecx,(%%ecx)
219 \\ sub $0x1000,%%eax
220 \\ cmp $0x1000,%%eax
221 \\ ja 2b
222 \\ 1:
223 \\ sub %%eax,%%ecx
224 \\ test %%ecx,(%%ecx)
225 \\ pop %%eax
226 \\ pop %%ecx
227 \\ ret
228 );
229 unreachable;
230 }
231
232 @setGlobalLinkage(__chkstk_ms, builtin.GlobalLinkage.Internal);
222 asm volatile (
223 \\ push %%ecx
224 \\ push %%eax
225 \\ cmp $0x1000,%%eax
226 \\ lea 12(%%esp),%%ecx
227 \\ jb 1f
228 \\ 2:
229 \\ sub $0x1000,%%ecx
230 \\ test %%ecx,(%%ecx)
231 \\ sub $0x1000,%%eax
232 \\ cmp $0x1000,%%eax
233 \\ ja 2b
234 \\ 1:
235 \\ sub %%eax,%%ecx
236 \\ test %%ecx,(%%ecx)
237 \\ pop %%eax
238 \\ pop %%ecx
239 \\ ret
240 );
233241}
234242
235export nakedcc fn ___chkstk_ms() align(4) {
243nakedcc fn ___chkstk_ms() align(4) {
236244 @setDebugSafety(this, false);
237245
238 if (win64_nocrt) {
239 @setGlobalLinkage(___chkstk_ms, linkage);
240 asm volatile (
241 \\ push %%rcx
242 \\ push %%rax
243 \\ cmp $0x1000,%%rax
244 \\ lea 24(%%rsp),%%rcx
245 \\ jb 1f
246 \\2:
247 \\ sub $0x1000,%%rcx
248 \\ test %%rcx,(%%rcx)
249 \\ sub $0x1000,%%rax
250 \\ cmp $0x1000,%%rax
251 \\ ja 2b
252 \\1:
253 \\ sub %%rax,%%rcx
254 \\ test %%rcx,(%%rcx)
255 \\ pop %%rax
256 \\ pop %%rcx
257 \\ ret
258 );
259 unreachable;
260 }
261
262 @setGlobalLinkage(___chkstk_ms, builtin.GlobalLinkage.Internal);
246 asm volatile (
247 \\ push %%rcx
248 \\ push %%rax
249 \\ cmp $0x1000,%%rax
250 \\ lea 24(%%rsp),%%rcx
251 \\ jb 1f
252 \\2:
253 \\ sub $0x1000,%%rcx
254 \\ test %%rcx,(%%rcx)
255 \\ sub $0x1000,%%rax
256 \\ cmp $0x1000,%%rax
257 \\ ja 2b
258 \\1:
259 \\ sub %%rax,%%rcx
260 \\ test %%rcx,(%%rcx)
261 \\ pop %%rax
262 \\ pop %%rcx
263 \\ ret
264 );
263265}
264266
265export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 {
267extern fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 {
266268 @setDebugSafety(this, is_test);
267 @setGlobalLinkage(__udivmodsi4, linkage);
268269
269270 const d = __udivsi3(a, b);
270271 *rem = u32(i32(a) -% (i32(d) * i32(b)));
......@@ -272,19 +273,8 @@ export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 {
272273}
273274
274275
275// TODO make this an alias instead of an extra function call
276// https://github.com/andrewrk/zig/issues/256
277
278export fn __aeabi_uidiv(n: u32, d: u32) -> u32 {
276extern fn __udivsi3(n: u32, d: u32) -> u32 {
279277 @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
289279 const n_uword_bits: c_uint = u32.bit_count;
290280 // special cases
......@@ -480,4 +470,3 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) {
480470 const q: u32 = __udivsi3(a, b);
481471 assert(q == expected_q);
482472}
483
std/special/compiler_rt/udivmoddi4.zig+1-3
......@@ -1,10 +1,8 @@
11const udivmod = @import("udivmod.zig").udivmod;
22const 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 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__udivmoddi4, linkage);
86 return udivmod(u64, a, b, maybe_rem);
97}
108
std/special/compiler_rt/udivmodti4.zig+1-3
......@@ -1,10 +1,8 @@
11const udivmod = @import("udivmod.zig").udivmod;
22const 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 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__udivmodti4, linkage);
86 return udivmod(u128, a, b, maybe_rem);
97}
108
std/special/compiler_rt/udivti3.zig+1-3
......@@ -1,9 +1,7 @@
11const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;
22const 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 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__udivti3, linkage);
86 return __udivmodti4(a, b, null);
97}
std/special/compiler_rt/umodti3.zig+1-3
......@@ -1,10 +1,8 @@
11const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;
22const 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 {
65 @setDebugSafety(this, builtin.is_test);
7 @setGlobalLinkage(__umodti3, linkage);
86 var r: u128 = undefined;
97 _ = __udivmodti4(a, b, &r);
108 return r;
test/behavior.zig+2-1
......@@ -7,6 +7,8 @@ comptime {
77 _ = @import("cases/bitcast.zig");
88 _ = @import("cases/bool.zig");
99 _ = @import("cases/bugs/394.zig");
10 _ = @import("cases/bugs/655.zig");
11 _ = @import("cases/bugs/656.zig");
1012 _ = @import("cases/cast.zig");
1113 _ = @import("cases/const_slice_child.zig");
1214 _ = @import("cases/defer.zig");
......@@ -18,7 +20,6 @@ comptime {
1820 _ = @import("cases/fn.zig");
1921 _ = @import("cases/for.zig");
2022 _ = @import("cases/generics.zig");
21 _ = @import("cases/goto.zig");
2223 _ = @import("cases/if.zig");
2324 _ = @import("cases/import.zig");
2425 _ = @import("cases/incomplete_struct_param_tld.zig");
test/cases/align.zig+9-9
......@@ -10,7 +10,7 @@ test "global variable alignment" {
1010 assert(@typeOf(slice) == []align(4) u8);
1111}
1212
13fn derp() align(@sizeOf(usize) * 2) -> i32 { 1234 }
13fn derp() align(@sizeOf(usize) * 2) -> i32 { return 1234; }
1414fn noop1() align(1) {}
1515fn noop4() align(4) {}
1616
......@@ -53,14 +53,14 @@ test "implicitly decreasing pointer alignment" {
5353 assert(addUnaligned(&a, &b) == 7);
5454}
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
5858test "implicitly decreasing slice alignment" {
5959 const a: u32 align(4) = 3;
6060 const b: u32 align(8) = 4;
6161 assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7);
6262}
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
6565test "specifying alignment allows pointer cast" {
6666 testBytesAlign(0x33);
......@@ -115,20 +115,20 @@ fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) -> i32, answer: i32) {
115115 assert(ptr() == answer);
116116}
117117
118fn alignedSmall() align(8) -> i32 { 1234 }
119fn alignedBig() align(16) -> i32 { 5678 }
118fn alignedSmall() align(8) -> i32 { return 1234; }
119fn alignedBig() align(16) -> i32 { return 5678; }
120120
121121
122122test "@alignCast functions" {
123123 assert(fnExpectsOnly1(simple4) == 0x19);
124124}
125125fn fnExpectsOnly1(ptr: fn()align(1) -> i32) -> i32 {
126 fnExpects4(@alignCast(4, ptr))
126 return fnExpects4(@alignCast(4, ptr));
127127}
128128fn fnExpects4(ptr: fn()align(4) -> i32) -> i32 {
129 ptr()
129 return ptr();
130130}
131fn simple4() align(4) -> i32 { 0x19 }
131fn simple4() align(4) -> i32 { return 0x19; }
132132
133133
134134test "generic function with align param" {
......@@ -137,7 +137,7 @@ test "generic function with align param" {
137137 assert(whyWouldYouEverDoThis(8) == 0x1);
138138}
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
143143test "@ptrCast preserves alignment of bigger source" {
test/cases/array.zig+2-2
......@@ -22,7 +22,7 @@ test "arrays" {
2222 assert(getArrayLen(array) == 5);
2323}
2424fn getArrayLen(a: []const u32) -> usize {
25 a.len
25 return a.len;
2626}
2727
2828test "void arrays" {
......@@ -41,7 +41,7 @@ test "array literal" {
4141}
4242
4343test "array dot len const expr" {
44 assert(comptime {some_array.len == 4});
44 assert(comptime x: {break :x some_array.len == 4;});
4545}
4646
4747const ArrayDotLenConstExpr = struct {
test/cases/bitcast.zig+2-2
......@@ -10,5 +10,5 @@ fn testBitCast_i32_u32() {
1010 assert(conv2(@maxValue(u32)) == -1);
1111}
1212
13fn conv(x: i32) -> u32 { @bitCast(u32, x) }
14fn conv2(x: u32) -> i32 { @bitCast(i32, x) }
13fn conv(x: i32) -> u32 { return @bitCast(u32, x); }
14fn conv2(x: u32) -> i32 { return @bitCast(i32, x); }
test/cases/bool.zig+1-1
......@@ -22,7 +22,7 @@ test "bool cmp" {
2222 assert(testBoolCmp(true, false) == false);
2323}
2424fn testBoolCmp(a: bool, b: bool) -> bool {
25 a == b
25 return a == b;
2626}
2727
2828const 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" {
5050 comptime assert(mem.eql(u8, boolToStr(false), "false"));
5151}
5252fn boolToStr(b: bool) -> []const u8 {
53 if (b) "true" else "false"
53 return if (b) "true" else "false";
5454}
5555
5656
......@@ -239,17 +239,17 @@ test "peer type resolution: error and [N]T" {
239239
240240error BadValue;
241241fn testPeerErrorAndArray(x: u8) -> %[]const u8 {
242 switch (x) {
242 return switch (x) {
243243 0x00 => "OK",
244244 else => error.BadValue,
245 }
245 };
246246}
247247fn testPeerErrorAndArray2(x: u8) -> %[]const u8 {
248 switch (x) {
248 return switch (x) {
249249 0x00 => "OK",
250250 0x01 => "OKK",
251251 else => error.BadValue,
252 }
252 };
253253}
254254
255255test "explicit cast float number literal to integer if no fraction component" {
......@@ -269,11 +269,11 @@ fn testCast128() {
269269}
270270
271271fn cast128Int(x: f128) -> u128 {
272 @bitCast(u128, x)
272 return @bitCast(u128, x);
273273}
274274
275275fn cast128Float(x: u128) -> f128 {
276 @bitCast(f128, x)
276 return @bitCast(f128, x);
277277}
278278
279279test "const slice widen cast" {
test/cases/defer.zig+6-6
......@@ -7,9 +7,9 @@ error FalseNotAllowed;
77
88fn runSomeErrorDefers(x: bool) -> %bool {
99 index = 0;
10 defer {result[index] = 'a'; index += 1;};
11 %defer {result[index] = 'b'; index += 1;};
12 defer {result[index] = 'c'; index += 1;};
10 defer {result[index] = 'a'; index += 1;}
11 %defer {result[index] = 'b'; index += 1;}
12 defer {result[index] = 'c'; index += 1;}
1313 return if (x) x else error.FalseNotAllowed;
1414}
1515
......@@ -18,9 +18,9 @@ test "mixing normal and error defers" {
1818 assert(result[0] == 'c');
1919 assert(result[1] == 'a');
2020
21 const ok = runSomeErrorDefers(false) %% |err| {
21 const ok = runSomeErrorDefers(false) %% |err| x: {
2222 assert(err == error.FalseNotAllowed);
23 true
23 break :x true;
2424 };
2525 assert(ok);
2626 assert(result[0] == 'c');
......@@ -41,5 +41,5 @@ fn testBreakContInDefer(x: usize) {
4141 if (i == 5) break;
4242 }
4343 assert(i == 5);
44 };
44 }
4545}
test/cases/enum.zig+34-1
......@@ -41,7 +41,7 @@ const Bar = enum {
4141};
4242
4343fn returnAnInt(x: i32) -> Foo {
44 Foo { .One = x }
44 return Foo { .One = x };
4545}
4646
4747
......@@ -344,3 +344,36 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) {
344344 MultipleChoice2.Unspecified5 => 9,
345345 });
346346}
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) {
88
99 pub fn print(a: &const ET, buf: []u8) -> %usize {
1010 return switch (*a) {
11 ET.SINT => |x| { fmt.formatIntBuf(buf, x, 10, false, 0) },
12 ET.UINT => |x| { fmt.formatIntBuf(buf, x, 10, false, 0) },
13 }
11 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
12 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
13 };
1414 }
1515};
1616
test/cases/error.zig+5-9
......@@ -3,7 +3,7 @@ const mem = @import("std").mem;
33
44pub fn foo() -> %i32 {
55 const x = %return bar();
6 return x + 1
6 return x + 1;
77}
88
99pub fn bar() -> %i32 {
......@@ -21,7 +21,7 @@ test "error wrapping" {
2121
2222error ItBroke;
2323fn gimmeItBroke() -> []const u8 {
24 @errorName(error.ItBroke)
24 return @errorName(error.ItBroke);
2525}
2626
2727test "@errorName" {
......@@ -48,7 +48,7 @@ error AnError;
4848error AnError;
4949error SecondError;
5050fn shouldBeNotEqual(a: error, b: error) {
51 if (a == b) unreachable
51 if (a == b) unreachable;
5252}
5353
5454
......@@ -60,11 +60,7 @@ test "error binary operator" {
6060}
6161error ItBroke;
6262fn errBinaryOperatorG(x: bool) -> %isize {
63 if (x) {
64 error.ItBroke
65 } else {
66 isize(10)
67 }
63 return if (x) error.ItBroke else isize(10);
6864}
6965
7066
......@@ -72,7 +68,7 @@ test "unwrap simple value from error" {
7268 const i = %%unwrapSimpleValueFromErrorDo();
7369 assert(i == 13);
7470}
75fn unwrapSimpleValueFromErrorDo() -> %isize { 13 }
71fn unwrapSimpleValueFromErrorDo() -> %isize { return 13; }
7672
7773
7874test "error return in assignment" {
test/cases/eval.zig+13-13
......@@ -44,7 +44,7 @@ test "static function evaluation" {
4444 assert(statically_added_number == 3);
4545}
4646const 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
5050test "const expr eval on single expr blocks" {
......@@ -54,10 +54,10 @@ test "const expr eval on single expr blocks" {
5454fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) -> i32 {
5555 const literal = 3;
5656
57 const result = if (b) {
58 literal
59 } else {
60 x
57 const result = if (b) b: {
58 break :b literal;
59 } else b: {
60 break :b x;
6161 };
6262
6363 return result;
......@@ -94,9 +94,9 @@ pub const Vec3 = struct {
9494 data: [3]f32,
9595};
9696pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 {
97 Vec3 {
97 return Vec3 {
9898 .data = []f32 { x, y, z, },
99 }
99 };
100100}
101101
102102
......@@ -176,7 +176,7 @@ fn max(comptime T: type, a: T, b: T) -> T {
176176 }
177177}
178178fn letsTryToCompareBools(a: bool, b: bool) -> bool {
179 max(bool, a, b)
179 return max(bool, a, b);
180180}
181181test "inlined block and runtime block phi" {
182182 assert(letsTryToCompareBools(true, true));
......@@ -202,9 +202,9 @@ const cmd_fns = []CmdFn{
202202 CmdFn {.name = "two", .func = two},
203203 CmdFn {.name = "three", .func = three},
204204};
205fn one(value: i32) -> i32 { value + 1 }
206fn two(value: i32) -> i32 { value + 2 }
207fn three(value: i32) -> i32 { value + 3 }
205fn one(value: i32) -> i32 { return value + 1; }
206fn two(value: i32) -> i32 { return value + 2; }
207fn three(value: i32) -> i32 { return value + 3; }
208208
209209fn performFn(comptime prefix_char: u8, start_value: i32) -> i32 {
210210 var result: i32 = start_value;
......@@ -317,12 +317,12 @@ test "create global array with for loop" {
317317 assert(global_array[9] == 9 * 9);
318318}
319319
320const global_array = {
320const global_array = x: {
321321 var result: [10]usize = undefined;
322322 for (result) |*item, index| {
323323 *item = index * index;
324324 }
325 result
325 break :x result;
326326};
327327
328328test "compile-time downcast when the bits fit" {
test/cases/fn.zig+10-10
......@@ -4,7 +4,7 @@ test "params" {
44 assert(testParamsAdd(22, 11) == 33);
55}
66fn testParamsAdd(a: i32, b: i32) -> i32 {
7 a + b
7 return a + b;
88}
99
1010
......@@ -22,7 +22,7 @@ test "void parameters" {
2222}
2323fn voidFun(a: i32, b: void, c: i32, d: void) {
2424 const v = b;
25 const vv: void = if (a == 1) {v} else {};
25 const vv: void = if (a == 1) v else {};
2626 assert(a + c == 3);
2727 return vv;
2828}
......@@ -45,9 +45,9 @@ test "separate block scopes" {
4545 assert(no_conflict == 5);
4646 }
4747
48 const c = {
48 const c = x: {
4949 const no_conflict = i32(10);
50 no_conflict
50 break :x no_conflict;
5151 };
5252 assert(c == 10);
5353}
......@@ -73,7 +73,7 @@ test "implicit cast function unreachable return" {
7373fn wantsFnWithVoid(f: fn()) { }
7474
7575fn fnWithUnreachable() -> noreturn {
76 unreachable
76 unreachable;
7777}
7878
7979
......@@ -83,14 +83,14 @@ test "function pointers" {
8383 assert(f() == u32(i) + 5);
8484 }
8585}
86fn fn1() -> u32 {5}
87fn fn2() -> u32 {6}
88fn fn3() -> u32 {7}
89fn fn4() -> u32 {8}
86fn fn1() -> u32 {return 5;}
87fn fn2() -> u32 {return 6;}
88fn fn3() -> u32 {return 7;}
89fn fn4() -> u32 {return 8;}
9090
9191
9292test "inline function call" {
9393 assert(@inlineCall(add, 3, 9) == 12);
9494}
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" {
1212 }
1313 break;
1414 }
15 if (sum != 6) unreachable
15 if (sum != 6) unreachable;
1616}
1717
1818test "for loop with pointer elem var" {
......@@ -55,3 +55,37 @@ test "basic for loop" {
5555
5656 assert(mem.eql(u8, buffer[0..buf_index], expected_result));
5757}
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 {
1111}
1212
1313fn add(comptime a: i32, b: i32) -> i32 {
14 return (comptime {a}) + b;
14 return (comptime a) + b;
1515}
1616
1717const the_max = max(u32, 1234, 5678);
......@@ -20,15 +20,15 @@ test "compile time generic eval" {
2020}
2121
2222fn gimmeTheBigOne(a: u32, b: u32) -> u32 {
23 max(u32, a, b)
23 return max(u32, a, b);
2424}
2525
2626fn shouldCallSameInstance(a: u32, b: u32) -> u32 {
27 max(u32, a, b)
27 return max(u32, a, b);
2828}
2929
3030fn sameButWithFloats(a: f64, b: f64) -> f64 {
31 max(f64, a, b)
31 return max(f64, a, b);
3232}
3333
3434test "fn with comptime args" {
......@@ -49,28 +49,28 @@ comptime {
4949}
5050
5151fn max_var(a: var, b: var) -> @typeOf(a + b) {
52 if (a > b) a else b
52 return if (a > b) a else b;
5353}
5454
5555fn max_i32(a: i32, b: i32) -> i32 {
56 max_var(a, b)
56 return max_var(a, b);
5757}
5858
5959fn max_f64(a: f64, b: f64) -> f64 {
60 max_var(a, b)
60 return max_var(a, b);
6161}
6262
6363
6464pub fn List(comptime T: type) -> type {
65 SmallList(T, 8)
65 return SmallList(T, 8);
6666}
6767
6868pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
69 struct {
69 return struct {
7070 items: []T,
7171 length: usize,
7272 prealloc_items: [STATIC_SIZE]T,
73 }
73 };
7474}
7575
7676test "function with return type type" {
......@@ -91,20 +91,20 @@ test "generic struct" {
9191 assert(b1.getVal());
9292}
9393fn GenNode(comptime T: type) -> type {
94 struct {
94 return struct {
9595 value: T,
9696 next: ?&GenNode(T),
97 fn getVal(n: &const GenNode(T)) -> T { n.value }
98 }
97 fn getVal(n: &const GenNode(T)) -> T { return n.value; }
98 };
9999}
100100
101101test "const decls in struct" {
102102 assert(GenericDataThing(3).count_plus_one == 4);
103103}
104104fn GenericDataThing(comptime count: isize) -> type {
105 struct {
105 return struct {
106106 const count_plus_one = count + 1;
107 }
107 };
108108}
109109
110110
......@@ -120,16 +120,16 @@ test "generic fn with implicit cast" {
120120 assert(getFirstByte(u8, []u8 {13}) == 13);
121121 assert(getFirstByte(u16, []u16 {0, 13}) == 0);
122122}
123fn getByte(ptr: ?&const u8) -> u8 {*??ptr}
123fn getByte(ptr: ?&const u8) -> u8 {return *??ptr;}
124124fn getFirstByte(comptime T: type, mem: []const T) -> u8 {
125 getByte(@ptrCast(&const u8, &mem[0]))
125 return getByte(@ptrCast(&const u8, &mem[0]));
126126}
127127
128128
129129const foos = []fn(var) -> bool { foo1, foo2 };
130130
131fn foo1(arg: var) -> bool { arg }
132fn foo2(arg: var) -> bool { !arg }
131fn foo1(arg: var) -> bool { return arg; }
132fn foo2(arg: var) -> bool { return !arg; }
133133
134134test "array of generic fns" {
135135 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" {
2929}
3030fn elseIfExpressionF(c: u8) -> u8 {
3131 if (c == 0) {
32 0
32 return 0;
3333 } else if (c == 1) {
34 1
34 return 1;
3535 } else {
36 u8(2)
36 return u8(2);
3737 }
3838}
test/cases/import/a_namespace.zig+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 {
88 return %return getErrInt();
99 },
1010 else => error.ItBroke,
11 }
11 };
1212}
1313
14fn getErrInt() -> %i32 { 0 }
14fn getErrInt() -> %i32 { return 0; }
1515
1616error ItBroke;
1717
test/cases/math.zig+11-11
......@@ -28,16 +28,16 @@ fn testDivision() {
2828 assert(divTrunc(f32, -5.0, 3.0) == -1.0);
2929}
3030fn div(comptime T: type, a: T, b: T) -> T {
31 a / b
31 return a / b;
3232}
3333fn divExact(comptime T: type, a: T, b: T) -> T {
34 @divExact(a, b)
34 return @divExact(a, b);
3535}
3636fn divFloor(comptime T: type, a: T, b: T) -> T {
37 @divFloor(a, b)
37 return @divFloor(a, b);
3838}
3939fn divTrunc(comptime T: type, a: T, b: T) -> T {
40 @divTrunc(a, b)
40 return @divTrunc(a, b);
4141}
4242
4343test "@addWithOverflow" {
......@@ -71,7 +71,7 @@ fn testClz() {
7171}
7272
7373fn clz(x: var) -> usize {
74 @clz(x)
74 return @clz(x);
7575}
7676
7777test "@ctz" {
......@@ -86,7 +86,7 @@ fn testCtz() {
8686}
8787
8888fn ctz(x: var) -> usize {
89 @ctz(x)
89 return @ctz(x);
9090}
9191
9292test "assignment operators" {
......@@ -180,10 +180,10 @@ fn test_u64_div() {
180180 assert(result.remainder == 100663296);
181181}
182182fn divWithResult(a: u64, b: u64) -> DivResult {
183 DivResult {
183 return DivResult {
184184 .quotient = a / b,
185185 .remainder = a % b,
186 }
186 };
187187}
188188const DivResult = struct {
189189 quotient: u64,
......@@ -191,8 +191,8 @@ const DivResult = struct {
191191};
192192
193193test "binary not" {
194 assert(comptime {~u16(0b1010101010101010) == 0b0101010101010101});
195 assert(comptime {~u64(2147483647) == 18446744071562067968});
194 assert(comptime x: {break :x ~u16(0b1010101010101010) == 0b0101010101010101;});
195 assert(comptime x: {break :x ~u64(2147483647) == 18446744071562067968;});
196196 testBinaryNot(0b1010101010101010);
197197}
198198
......@@ -331,7 +331,7 @@ test "f128" {
331331 comptime test_f128();
332332}
333333
334fn make_f128(x: f128) -> f128 { x }
334fn make_f128(x: f128) -> f128 { return x; }
335335
336336fn test_f128() {
337337 assert(@sizeOf(f128) == 16);
test/cases/misc.zig+21-18
......@@ -12,8 +12,11 @@ test "empty function with comments" {
1212 emptyFunctionWithComments();
1313}
1414
15export fn disabledExternFn() {
16 @setGlobalLinkage(disabledExternFn, builtin.GlobalLinkage.Internal);
15comptime {
16 @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
17}
18
19extern fn disabledExternFn() {
1720}
1821
1922test "call disabled extern fn" {
......@@ -107,17 +110,17 @@ fn testShortCircuit(f: bool, t: bool) {
107110 var hit_3 = f;
108111 var hit_4 = f;
109112
110 if (t or {assert(f); f}) {
113 if (t or x: {assert(f); break :x f;}) {
111114 hit_1 = t;
112115 }
113 if (f or { hit_2 = t; f }) {
116 if (f or x: { hit_2 = t; break :x f; }) {
114117 assert(f);
115118 }
116119
117 if (t and { hit_3 = t; f }) {
120 if (t and x: { hit_3 = t; break :x f; }) {
118121 assert(f);
119122 }
120 if (f and {assert(f); f}) {
123 if (f and x: {assert(f); break :x f;}) {
121124 assert(f);
122125 } else {
123126 hit_4 = t;
......@@ -132,11 +135,11 @@ test "truncate" {
132135 assert(testTruncate(0x10fd) == 0xfd);
133136}
134137fn testTruncate(x: u32) -> u8 {
135 @truncate(u8, x)
138 return @truncate(u8, x);
136139}
137140
138141fn first4KeysOfHomeRow() -> []const u8 {
139 "aoeu"
142 return "aoeu";
140143}
141144
142145test "return string from function" {
......@@ -164,7 +167,7 @@ test "memcpy and memset intrinsics" {
164167}
165168
166169test "builtin static eval" {
167 const x : i32 = comptime {1 + 2 + 3};
170 const x : i32 = comptime x: {break :x 1 + 2 + 3;};
168171 assert(x == comptime 6);
169172}
170173
......@@ -187,7 +190,7 @@ test "slicing" {
187190
188191test "constant equal function pointers" {
189192 const alias = emptyFn;
190 assert(comptime {emptyFn == alias});
193 assert(comptime x: {break :x emptyFn == alias;});
191194}
192195
193196fn emptyFn() {}
......@@ -277,14 +280,14 @@ test "cast small unsigned to larger signed" {
277280 assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
278281 assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
279282}
280fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { x }
281fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { x }
283fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { return x; }
284fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { return x; }
282285
283286
284287test "implicit cast after unreachable" {
285288 assert(outer() == 1234);
286289}
287fn inner() -> i32 { 1234 }
290fn inner() -> i32 { return 1234; }
288291fn outer() -> i64 {
289292 return inner();
290293}
......@@ -307,8 +310,8 @@ test "call result of if else expression" {
307310fn f2(x: bool) -> []const u8 {
308311 return (if (x) fA else fB)();
309312}
310fn fA() -> []const u8 { "a" }
311fn fB() -> []const u8 { "b" }
313fn fA() -> []const u8 { return "a"; }
314fn fB() -> []const u8 { return "b"; }
312315
313316
314317test "const expression eval handling of variables" {
......@@ -376,7 +379,7 @@ test "pointer comparison" {
376379 assert(ptrEql(b, b));
377380}
378381fn ptrEql(a: &const []const u8, b: &const []const u8) -> bool {
379 a == b
382 return a == b;
380383}
381384
382385
......@@ -480,7 +483,7 @@ test "@typeId" {
480483 assert(@typeId(AUnion) == Tid.Union);
481484 assert(@typeId(fn()) == Tid.Fn);
482485 assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
483 assert(@typeId(@typeOf({this})) == Tid.Block);
486 assert(@typeId(@typeOf(x: {break :x this;})) == Tid.Block);
484487 // TODO bound fn
485488 // TODO arg tuple
486489 // TODO opaque
......@@ -504,7 +507,7 @@ test "@typeName" {
504507
505508test "volatile load and store" {
506509 var number: i32 = 1234;
507 const ptr = &volatile number;
510 const ptr = (&volatile i32)(&number);
508511 *ptr += 1;
509512 assert(*ptr == 1235);
510513}
test/cases/reflection.zig+1-1
......@@ -22,7 +22,7 @@ test "reflection: function return type, var args, and param types" {
2222 }
2323}
2424
25fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }
25fn dummy(a: bool, b: i32, c: f32) -> i32 { return 1234; }
2626fn dummy_varargs(args: ...) {}
2727
2828test "reflection: struct member types and names" {
test/cases/slice.zig+19
......@@ -1,4 +1,5 @@
11const assert = @import("std").debug.assert;
2const mem = @import("std").mem;
23
34const x = @intToPtr(&i32, 0x1000)[0..0x500];
45const y = x[0x100..];
......@@ -15,3 +16,21 @@ test "slice child property" {
1516 var slice = array[0..];
1617 assert(@typeOf(slice).Child == i32);
1718}
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;
22const builtin = @import("builtin");
33
44const StructWithNoFields = struct {
5 fn add(a: i32, b: i32) -> i32 { a + b }
5 fn add(a: i32, b: i32) -> i32 { return a + b; }
66};
77const empty_global_instance = StructWithNoFields {};
88
......@@ -109,7 +109,7 @@ const Foo = struct {
109109 ptr: fn() -> i32,
110110};
111111
112fn aFunc() -> i32 { 13 }
112fn aFunc() -> i32 { return 13; }
113113
114114fn callStructField(foo: &const Foo) -> i32 {
115115 return foo.ptr();
......@@ -124,7 +124,7 @@ test "store member function in variable" {
124124}
125125const MemberFnTestFoo = struct {
126126 x: i32,
127 fn member(foo: &const MemberFnTestFoo) -> i32 { foo.x }
127 fn member(foo: &const MemberFnTestFoo) -> i32 { return foo.x; }
128128};
129129
130130
......@@ -141,7 +141,7 @@ test "member functions" {
141141const MemberFnRand = struct {
142142 seed: u32,
143143 pub fn getSeed(r: &const MemberFnRand) -> u32 {
144 r.seed
144 return r.seed;
145145 }
146146};
147147
......@@ -154,10 +154,10 @@ const Bar = struct {
154154 y: i32,
155155};
156156fn makeBar(x: i32, y: i32) -> Bar {
157 Bar {
157 return Bar {
158158 .x = x,
159159 .y = y,
160 }
160 };
161161}
162162
163163test "empty struct method call" {
......@@ -166,7 +166,7 @@ test "empty struct method call" {
166166}
167167const EmptyStruct = struct {
168168 fn method(es: &const EmptyStruct) -> i32 {
169 1234
169 return 1234;
170170 }
171171};
172172
......@@ -176,14 +176,14 @@ test "return empty struct from fn" {
176176}
177177const EmptyStruct2 = struct {};
178178fn testReturnEmptyStructFromFn() -> EmptyStruct2 {
179 EmptyStruct2 {}
179 return EmptyStruct2 {};
180180}
181181
182182test "pass slice of empty struct to fn" {
183183 assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1);
184184}
185185fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) -> usize {
186 slice.len
186 return slice.len;
187187}
188188
189189const APackedStruct = packed struct {
......@@ -379,3 +379,28 @@ const Nibbles = packed struct {
379379 x: u4,
380380 y: u4,
381381};
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" {
2121}
2222
2323fn testSwitchWithAllRanges(x: u32, y: u32) -> u32 {
24 switch (x) {
24 return switch (x) {
2525 0 ... 100 => 1,
2626 101 ... 200 => 2,
2727 201 ... 300 => 3,
2828 else => y,
29 }
29 };
3030}
3131
3232test "implicit comptime switch" {
......@@ -132,7 +132,7 @@ test "switch with multiple expressions" {
132132 assert(x == 2);
133133}
134134fn returnsFive() -> i32 {
135 5
135 return 5;
136136}
137137
138138
......@@ -161,10 +161,10 @@ test "switch on type" {
161161}
162162
163163fn trueIfBoolFalseOtherwise(comptime T: type) -> bool {
164 switch (T) {
164 return switch (T) {
165165 bool => true,
166166 else => false,
167 }
167 };
168168}
169169
170170test "switch handles all cases of number" {
......@@ -186,22 +186,22 @@ fn testSwitchHandleAllCases() {
186186}
187187
188188fn testSwitchHandleAllCasesExhaustive(x: u2) -> u2 {
189 switch (x) {
189 return switch (x) {
190190 0 => u2(3),
191191 1 => 2,
192192 2 => 1,
193193 3 => 0,
194 }
194 };
195195}
196196
197197fn testSwitchHandleAllCasesRange(x: u8) -> u8 {
198 switch (x) {
198 return switch (x) {
199199 0 ... 100 => u8(0),
200200 101 ... 200 => 1,
201201 201, 203 => 2,
202202 202 => 4,
203203 204 ... 255 => 3,
204 }
204 };
205205}
206206
207207test "switch all prongs unreachable" {
test/cases/switch_prong_err_enum.zig+1-1
......@@ -18,7 +18,7 @@ fn doThing(form_id: u64) -> %FormValue {
1818 return switch (form_id) {
1919 17 => FormValue { .Address = %return readOnce() },
2020 else => error.InvalidDebugInfo,
21 }
21 };
2222}
2323
2424test "switch prong returns error enum" {
test/cases/switch_prong_implicit_cast.zig+2-2
......@@ -8,11 +8,11 @@ const FormValue = union(enum) {
88error Whatever;
99
1010fn foo(id: u64) -> %FormValue {
11 switch (id) {
11 return switch (id) {
1212 2 => FormValue { .Two = true },
1313 1 => FormValue { .One = {} },
1414 else => return error.Whatever,
15 }
15 };
1616}
1717
1818test "switch prong implicit cast" {
test/cases/this.zig+4-8
......@@ -3,7 +3,7 @@ const assert = @import("std").debug.assert;
33const module = this;
44
55fn Point(comptime T: type) -> type {
6 struct {
6 return struct {
77 const Self = this;
88 x: T,
99 y: T,
......@@ -12,20 +12,16 @@ fn Point(comptime T: type) -> type {
1212 self.x += 1;
1313 self.y += 1;
1414 }
15 }
15 };
1616}
1717
1818fn add(x: i32, y: i32) -> i32 {
19 x + y
19 return x + y;
2020}
2121
2222fn factorial(x: i32) -> i32 {
2323 const selfFn = this;
24 if (x == 0) {
25 1
26 } else {
27 x * selfFn(x - 1)
28 }
24 return if (x == 0) 1 else x * selfFn(x - 1);
2925}
3026
3127test "this refer to module call private fn" {
test/cases/try.zig+5-13
......@@ -7,9 +7,9 @@ test "try on error union" {
77}
88
99fn tryOnErrorUnionImpl() {
10 const x = if (returnsTen()) |val| {
10 const x = if (returnsTen()) |val|
1111 val + 1
12 } else |err| switch (err) {
12 else |err| switch (err) {
1313 error.ItBroke, error.NoMem => 1,
1414 error.CrappedOut => i32(2),
1515 else => unreachable,
......@@ -21,22 +21,14 @@ error ItBroke;
2121error NoMem;
2222error CrappedOut;
2323fn returnsTen() -> %i32 {
24 10
24 return 10;
2525}
2626
2727test "try without vars" {
28 const result1 = if (failIfTrue(true)) {
29 1
30 } else |_| {
31 i32(2)
32 };
28 const result1 = if (failIfTrue(true)) 1 else |_| i32(2);
3329 assert(result1 == 2);
3430
35 const result2 = if (failIfTrue(false)) {
36 1
37 } else |_| {
38 i32(2)
39 };
31 const result2 = if (failIfTrue(false)) 1 else |_| i32(2);
4032 assert(result2 == 1);
4133}
4234
test/cases/union.zig+30
......@@ -190,3 +190,33 @@ test "cast union to tag type of union" {
190190fn testCastUnionToTagType(x: &const TheUnion) {
191191 assert(TheTag(*x) == TheTag.B);
192192}
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 {
5858
5959const foos = []fn(...) -> bool { foo1, foo2 };
6060
61fn foo1(args: ...) -> bool { true }
62fn foo2(args: ...) -> bool { false }
61fn foo1(args: ...) -> bool { return true; }
62fn foo2(args: ...) -> bool { return false; }
6363
6464test "array of var args functions" {
6565 assert(foos[0]());
test/cases/while.zig+45-30
......@@ -118,80 +118,95 @@ test "while with error union condition" {
118118var numbers_left: i32 = undefined;
119119error OutOfNumbers;
120120fn getNumberOrErr() -> %i32 {
121 return if (numbers_left == 0) {
121 return if (numbers_left == 0)
122122 error.OutOfNumbers
123 } else {
123 else x: {
124124 numbers_left -= 1;
125 numbers_left
125 break :x numbers_left;
126126 };
127127}
128128fn getNumberOrNull() -> ?i32 {
129 return if (numbers_left == 0) {
129 return if (numbers_left == 0)
130130 null
131 } else {
131 else x: {
132132 numbers_left -= 1;
133 numbers_left
133 break :x numbers_left;
134134 };
135135}
136136
137137test "while on nullable with else result follow else prong" {
138138 const result = while (returnNull()) |value| {
139139 break value;
140 } else {
141 i32(2)
142 };
140 } else i32(2);
143141 assert(result == 2);
144142}
145143
146144test "while on nullable with else result follow break prong" {
147145 const result = while (returnMaybe(10)) |value| {
148146 break value;
149 } else {
150 i32(2)
151 };
147 } else i32(2);
152148 assert(result == 10);
153149}
154150
155151test "while on error union with else result follow else prong" {
156152 const result = while (returnError()) |value| {
157153 break value;
158 } else |err| {
159 i32(2)
160 };
154 } else |err| i32(2);
161155 assert(result == 2);
162156}
163157
164158test "while on error union with else result follow break prong" {
165159 const result = while (returnSuccess(10)) |value| {
166160 break value;
167 } else |err| {
168 i32(2)
169 };
161 } else |err| i32(2);
170162 assert(result == 10);
171163}
172164
173165test "while on bool with else result follow else prong" {
174166 const result = while (returnFalse()) {
175167 break i32(10);
176 } else {
177 i32(2)
178 };
168 } else i32(2);
179169 assert(result == 2);
180170}
181171
182172test "while on bool with else result follow break prong" {
183173 const result = while (returnTrue()) {
184174 break i32(10);
185 } else {
186 i32(2)
187 };
175 } else i32(2);
188176 assert(result == 10);
189177}
190178
191fn returnNull() -> ?i32 { null }
192fn returnMaybe(x: i32) -> ?i32 { x }
179test "break from outer while loop" {
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; }
193208error YouWantedAnError;
194fn returnError() -> %i32 { error.YouWantedAnError }
195fn returnSuccess(x: i32) -> %i32 { x }
196fn returnFalse() -> bool { false }
197fn returnTrue() -> bool { true }
209fn returnError() -> %i32 { return error.YouWantedAnError; }
210fn returnSuccess(x: i32) -> %i32 { return x; }
211fn returnFalse() -> bool { return false; }
212fn returnTrue() -> bool { return true; }
test/compare_output.zig+95-13
......@@ -10,7 +10,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
1010 \\}
1111 , "Hello, world!" ++ os.line_sep);
1212
13 cases.addCase({
13 cases.addCase(x: {
1414 var tc = cases.create("multiple files with private function",
1515 \\use @import("std").io;
1616 \\use @import("foo.zig");
......@@ -41,10 +41,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
4141 \\}
4242 );
4343
44 tc
44 break :x tc;
4545 });
4646
47 cases.addCase({
47 cases.addCase(x: {
4848 var tc = cases.create("import segregation",
4949 \\use @import("foo.zig");
5050 \\use @import("bar.zig");
......@@ -82,10 +82,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
8282 \\}
8383 );
8484
85 tc
85 break :x tc;
8686 });
8787
88 cases.addCase({
88 cases.addCase(x: {
8989 var tc = cases.create("two files use import each other",
9090 \\use @import("a.zig");
9191 \\
......@@ -112,7 +112,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
112112 \\pub const b_text = a_text;
113113 );
114114
115 tc
115 break :x tc;
116116 });
117117
118118 cases.add("hello world without libc",
......@@ -286,11 +286,11 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
286286 \\ const a_int = @ptrCast(&align(1) i32, a ?? unreachable);
287287 \\ const b_int = @ptrCast(&align(1) i32, b ?? unreachable);
288288 \\ if (*a_int < *b_int) {
289 \\ -1
289 \\ return -1;
290290 \\ } else if (*a_int > *b_int) {
291 \\ 1
291 \\ return 1;
292292 \\ } else {
293 \\ c_int(0)
293 \\ return 0;
294294 \\ }
295295 \\}
296296 \\
......@@ -342,13 +342,13 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
342342 \\const Foo = struct {
343343 \\ field1: Bar,
344344 \\
345 \\ fn method(a: &const Foo) -> bool { true }
345 \\ fn method(a: &const Foo) -> bool { return true; }
346346 \\};
347347 \\
348348 \\const Bar = struct {
349349 \\ field2: i32,
350350 \\
351 \\ fn method(b: &const Bar) -> bool { true }
351 \\ fn method(b: &const Bar) -> bool { return true; }
352352 \\};
353353 \\
354354 \\pub fn main() -> %void {
......@@ -429,7 +429,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
429429 \\fn its_gonna_pass() -> %void { }
430430 , "before\nafter\ndefer3\ndefer1\n");
431431
432 cases.addCase({
432 cases.addCase(x: {
433433 var tc = cases.create("@embedFile",
434434 \\const foo_txt = @embedFile("foo.txt");
435435 \\const io = @import("std").io;
......@@ -442,6 +442,88 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
442442
443443 tc.addSourceFile("foo.txt", "1234\nabcd\n");
444444
445 tc
445 break :x tc;
446 });
447
448 cases.addCase(x: {
449 var tc = cases.create("parsing args",
450 \\const std = @import("std");
451 \\const io = std.io;
452 \\const os = std.os;
453 \\const allocator = std.debug.global_allocator;
454 \\
455 \\pub fn main() -> %void {
456 \\ var args_it = os.args();
457 \\ var stdout_file = %return io.getStdOut();
458 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
459 \\ const stdout = &stdout_adapter.stream;
460 \\ var index: usize = 0;
461 \\ _ = args_it.skip();
462 \\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) {
463 \\ const arg = %return arg_or_err;
464 \\ %return stdout.print("{}: {}\n", index, arg);
465 \\ }
466 \\}
467 ,
468 \\0: first arg
469 \\1: 'a' 'b' \
470 \\2: bare
471 \\3: ba""re
472 \\4: "
473 \\5: last arg
474 \\
475 );
476
477 tc.setCommandLineArgs([][]const u8 {
478 "first arg",
479 "'a' 'b' \\",
480 "bare",
481 "ba\"\"re",
482 "\"",
483 "last arg",
484 });
485
486 break :x tc;
487 });
488
489 cases.addCase(x: {
490 var tc = cases.create("parsing args new API",
491 \\const std = @import("std");
492 \\const io = std.io;
493 \\const os = std.os;
494 \\const allocator = std.debug.global_allocator;
495 \\
496 \\pub fn main() -> %void {
497 \\ var args_it = os.args();
498 \\ var stdout_file = %return io.getStdOut();
499 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
500 \\ const stdout = &stdout_adapter.stream;
501 \\ var index: usize = 0;
502 \\ _ = args_it.skip();
503 \\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) {
504 \\ const arg = %return arg_or_err;
505 \\ %return stdout.print("{}: {}\n", index, arg);
506 \\ }
507 \\}
508 ,
509 \\0: first arg
510 \\1: 'a' 'b' \
511 \\2: bare
512 \\3: ba""re
513 \\4: "
514 \\5: last arg
515 \\
516 );
517
518 tc.setCommandLineArgs([][]const u8 {
519 "first arg",
520 "'a' 'b' \\",
521 "bare",
522 "ba\"\"re",
523 "\"",
524 "last arg",
525 });
526
527 break :x tc;
446528 });
447529}
test/compile_errors.zig+276-224
......@@ -1,6 +1,37 @@
11const tests = @import("tests.zig");
22
33pub 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
435 cases.add("implicit semicolon - block statement",
536 \\export fn entry() {
637 \\ {}
......@@ -8,7 +39,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
839 \\ ({})
940 \\ var bad = {};
1041 \\}
11 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
42 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1243
1344 cases.add("implicit semicolon - block expr",
1445 \\export fn entry() {
......@@ -17,7 +48,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1748 \\ _ = {}
1849 \\ var bad = {};
1950 \\}
20 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
51 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
2152
2253 cases.add("implicit semicolon - comptime statement",
2354 \\export fn entry() {
......@@ -26,7 +57,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
2657 \\ comptime ({})
2758 \\ var bad = {};
2859 \\}
29 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
60 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
3061
3162 cases.add("implicit semicolon - comptime expression",
3263 \\export fn entry() {
......@@ -35,7 +66,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
3566 \\ _ = comptime {}
3667 \\ var bad = {};
3768 \\}
38 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
69 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
3970
4071 cases.add("implicit semicolon - defer",
4172 \\export fn entry() {
......@@ -53,7 +84,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
5384 \\ if(true) ({})
5485 \\ var bad = {};
5586 \\}
56 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
87 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
5788
5889 cases.add("implicit semicolon - if expression",
5990 \\export fn entry() {
......@@ -62,7 +93,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
6293 \\ _ = if(true) {}
6394 \\ var bad = {};
6495 \\}
65 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
96 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
6697
6798 cases.add("implicit semicolon - if-else statement",
6899 \\export fn entry() {
......@@ -71,7 +102,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
71102 \\ if(true) ({}) else ({})
72103 \\ var bad = {};
73104 \\}
74 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
105 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
75106
76107 cases.add("implicit semicolon - if-else expression",
77108 \\export fn entry() {
......@@ -80,7 +111,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
80111 \\ _ = if(true) {} else {}
81112 \\ var bad = {};
82113 \\}
83 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
114 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
84115
85116 cases.add("implicit semicolon - if-else-if statement",
86117 \\export fn entry() {
......@@ -89,7 +120,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
89120 \\ if(true) ({}) else if(true) ({})
90121 \\ var bad = {};
91122 \\}
92 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
123 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
93124
94125 cases.add("implicit semicolon - if-else-if expression",
95126 \\export fn entry() {
......@@ -98,7 +129,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
98129 \\ _ = if(true) {} else if(true) {}
99130 \\ var bad = {};
100131 \\}
101 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
132 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
102133
103134 cases.add("implicit semicolon - if-else-if-else statement",
104135 \\export fn entry() {
......@@ -107,7 +138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
107138 \\ if(true) ({}) else if(true) ({}) else ({})
108139 \\ var bad = {};
109140 \\}
110 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
141 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
111142
112143 cases.add("implicit semicolon - if-else-if-else expression",
113144 \\export fn entry() {
......@@ -116,7 +147,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
116147 \\ _ = if(true) {} else if(true) {} else {}
117148 \\ var bad = {};
118149 \\}
119 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
150 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
120151
121152 cases.add("implicit semicolon - test statement",
122153 \\export fn entry() {
......@@ -125,7 +156,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
125156 \\ if (foo()) |_| ({})
126157 \\ var bad = {};
127158 \\}
128 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
159 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
129160
130161 cases.add("implicit semicolon - test expression",
131162 \\export fn entry() {
......@@ -134,7 +165,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
134165 \\ _ = if (foo()) |_| {}
135166 \\ var bad = {};
136167 \\}
137 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
168 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
138169
139170 cases.add("implicit semicolon - while statement",
140171 \\export fn entry() {
......@@ -143,7 +174,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
143174 \\ while(true) ({})
144175 \\ var bad = {};
145176 \\}
146 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
177 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
147178
148179 cases.add("implicit semicolon - while expression",
149180 \\export fn entry() {
......@@ -152,7 +183,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
152183 \\ _ = while(true) {}
153184 \\ var bad = {};
154185 \\}
155 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
186 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
156187
157188 cases.add("implicit semicolon - while-continue statement",
158189 \\export fn entry() {
......@@ -161,7 +192,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
161192 \\ while(true):({}) ({})
162193 \\ var bad = {};
163194 \\}
164 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
195 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
165196
166197 cases.add("implicit semicolon - while-continue expression",
167198 \\export fn entry() {
......@@ -170,7 +201,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
170201 \\ _ = while(true):({}) {}
171202 \\ var bad = {};
172203 \\}
173 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
204 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
174205
175206 cases.add("implicit semicolon - for statement",
176207 \\export fn entry() {
......@@ -179,7 +210,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
179210 \\ for(foo()) ({})
180211 \\ var bad = {};
181212 \\}
182 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
213 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
183214
184215 cases.add("implicit semicolon - for expression",
185216 \\export fn entry() {
......@@ -188,7 +219,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
188219 \\ _ = for(foo()) {}
189220 \\ var bad = {};
190221 \\}
191 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
222 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
192223
193224 cases.add("multiple function definitions",
194225 \\fn a() {}
......@@ -245,12 +276,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
245276
246277 cases.add("undeclared identifier",
247278 \\export fn a() {
279 \\ return
248280 \\ b +
249 \\ c
281 \\ c;
250282 \\}
251283 ,
252 ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",
253 ".tmp_source.zig:3:5: error: use of undeclared identifier 'c'");
284 ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'",
285 ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'");
254286
255287 cases.add("parameter redeclaration",
256288 \\fn f(a : i32, a : i32) {
......@@ -275,9 +307,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
275307 cases.add("variable has wrong type",
276308 \\export fn f() -> i32 {
277309 \\ const a = c"a";
278 \\ a
310 \\ return a;
279311 \\}
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
282314 cases.add("if condition is bool, not int",
283315 \\export fn f() {
......@@ -362,23 +394,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
362394
363395 cases.add("missing else clause",
364396 \\fn f(b: bool) {
365 \\ const x : i32 = if (b) { 1 };
366 \\ const y = if (b) { i32(1) };
397 \\ const x : i32 = if (b) h: { break :h 1; };
398 \\ const y = if (b) h: { break :h i32(1); };
367399 \\}
368400 \\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'",
370402 ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'");
371403
372404 cases.add("direct struct loop",
373405 \\const A = struct { a : A, };
374 \\export fn entry() -> usize { @sizeOf(A) }
406 \\export fn entry() -> usize { return @sizeOf(A); }
375407 , ".tmp_source.zig:1:11: error: struct 'A' contains itself");
376408
377409 cases.add("indirect struct loop",
378410 \\const A = struct { b : B, };
379411 \\const B = struct { c : C, };
380412 \\const C = struct { a : A, };
381 \\export fn entry() -> usize { @sizeOf(A) }
413 \\export fn entry() -> usize { return @sizeOf(A); }
382414 , ".tmp_source.zig:1:11: error: struct 'A' contains itself");
383415
384416 cases.add("invalid struct field",
......@@ -476,10 +508,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
476508
477509 cases.add("cast unreachable",
478510 \\fn f() -> i32 {
479 \\ i32(return 1)
511 \\ return i32(return 1);
480512 \\}
481513 \\export fn entry() { _ = f(); }
482 , ".tmp_source.zig:2:8: error: unreachable code");
514 , ".tmp_source.zig:2:15: error: unreachable code");
483515
484516 cases.add("invalid builtin fn",
485517 \\fn f() -> @bogus(foo) {
......@@ -502,7 +534,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
502534
503535 cases.add("struct init syntax for array",
504536 \\const foo = []u16{.x = 1024,};
505 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
537 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
506538 , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax");
507539
508540 cases.add("type variables must be constant",
......@@ -545,7 +577,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
545577 \\ }
546578 \\}
547579 \\
548 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
580 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
549581 , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch");
550582
551583 cases.add("switch expression - duplicate enumeration prong",
......@@ -565,7 +597,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
565597 \\ }
566598 \\}
567599 \\
568 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
600 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
569601 , ".tmp_source.zig:13:15: error: duplicate switch value",
570602 ".tmp_source.zig:10:15: note: other value is here");
571603
......@@ -587,7 +619,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
587619 \\ }
588620 \\}
589621 \\
590 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
622 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
591623 , ".tmp_source.zig:13:15: error: duplicate switch value",
592624 ".tmp_source.zig:10:15: note: other value is here");
593625
......@@ -610,20 +642,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
610642 \\ 0 => {},
611643 \\ }
612644 \\}
613 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
645 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
614646 ,
615647 ".tmp_source.zig:2:5: error: switch must handle all possibilities");
616648
617649 cases.add("switch expression - duplicate or overlapping integer value",
618650 \\fn foo(x: u8) -> u8 {
619 \\ switch (x) {
651 \\ return switch (x) {
620652 \\ 0 ... 100 => u8(0),
621653 \\ 101 ... 200 => 1,
622654 \\ 201, 203 ... 207 => 2,
623655 \\ 206 ... 255 => 3,
624 \\ }
656 \\ };
625657 \\}
626 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
658 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
627659 ,
628660 ".tmp_source.zig:6:9: error: duplicate switch value",
629661 ".tmp_source.zig:5:14: note: previous value is here");
......@@ -635,14 +667,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
635667 \\ }
636668 \\}
637669 \\const y: u8 = 100;
638 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
670 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
639671 ,
640672 ".tmp_source.zig:2:5: error: else prong required when switching on type '&u8'");
641673
642674 cases.add("global variable initializer must be constant expression",
643675 \\extern fn foo() -> i32;
644676 \\const x = foo();
645 \\export fn entry() -> i32 { x }
677 \\export fn entry() -> i32 { return x; }
646678 , ".tmp_source.zig:2:11: error: unable to evaluate constant expression");
647679
648680 cases.add("array concatenation with wrong type",
......@@ -650,38 +682,38 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
650682 \\const derp = usize(1234);
651683 \\const a = derp ++ "foo";
652684 \\
653 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
685 \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
654686 , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'");
655687
656688 cases.add("non compile time array concatenation",
657689 \\fn f() -> []u8 {
658 \\ s ++ "foo"
690 \\ return s ++ "foo";
659691 \\}
660692 \\var s: [10]u8 = undefined;
661 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
662 , ".tmp_source.zig:2:5: error: unable to evaluate constant expression");
693 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
694 , ".tmp_source.zig:2:12: error: unable to evaluate constant expression");
663695
664696 cases.add("@cImport with bogus include",
665697 \\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)); }
667699 , ".tmp_source.zig:1:11: error: C import failed",
668700 ".h:1:10: note: 'bogus.h' file not found");
669701
670702 cases.add("address of number literal",
671703 \\const x = 3;
672704 \\const y = &x;
673 \\fn foo() -> &const i32 { y }
674 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
675 , ".tmp_source.zig:3:26: error: expected type '&const i32', found '&const (integer literal)'");
705 \\fn foo() -> &const i32 { return y; }
706 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
707 , ".tmp_source.zig:3:33: error: expected type '&const i32', found '&const (integer literal)'");
676708
677709 cases.add("integer overflow error",
678710 \\const x : u8 = 300;
679 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
711 \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
680712 , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'");
681713
682714 cases.add("incompatible number literals",
683715 \\const x = 2 == 2.0;
684 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
716 \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
685717 , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'");
686718
687719 cases.add("missing function call param",
......@@ -707,32 +739,32 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
707739 \\ const result = members[index]();
708740 \\}
709741 \\
710 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
742 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
711743 , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0");
712744
713745 cases.add("missing function name and param name",
714746 \\fn () {}
715747 \\fn f(i32) {}
716 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
748 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
717749 ,
718750 ".tmp_source.zig:1:1: error: missing function name",
719751 ".tmp_source.zig:2:6: error: missing parameter name");
720752
721753 cases.add("wrong function type",
722754 \\const fns = []fn(){ a, b, c };
723 \\fn a() -> i32 {0}
724 \\fn b() -> i32 {1}
725 \\fn c() -> i32 {2}
726 \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) }
755 \\fn a() -> i32 {return 0;}
756 \\fn b() -> i32 {return 1;}
757 \\fn c() -> i32 {return 2;}
758 \\export fn entry() -> usize { return @sizeOf(@typeOf(fns)); }
727759 , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'");
728760
729761 cases.add("extern function pointer mismatch",
730762 \\const fns = [](fn(i32)->i32){ a, b, c };
731 \\pub fn a(x: i32) -> i32 {x + 0}
732 \\pub fn b(x: i32) -> i32 {x + 1}
733 \\export fn c(x: i32) -> i32 {x + 2}
763 \\pub fn a(x: i32) -> i32 {return x + 0;}
764 \\pub fn b(x: i32) -> i32 {return x + 1;}
765 \\export fn c(x: i32) -> i32 {return x + 2;}
734766 \\
735 \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) }
767 \\export fn entry() -> usize { return @sizeOf(@typeOf(fns)); }
736768 , ".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) {
740772 \\const x : f64 = 1.0;
741773 \\const y : f32 = x;
742774 \\
743 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
775 \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
744776 , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'");
745777
746778
747779 cases.add("colliding invalid top level functions",
748780 \\fn func() -> bogus {}
749781 \\fn func() -> bogus {}
750 \\export fn entry() -> usize { @sizeOf(@typeOf(func)) }
782 \\export fn entry() -> usize { return @sizeOf(@typeOf(func)); }
751783 ,
752784 ".tmp_source.zig:2:1: error: redefinition of 'func'",
753785 ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'");
......@@ -755,7 +787,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
755787
756788 cases.add("bogus compile var",
757789 \\const x = @import("builtin").bogus;
758 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
790 \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
759791 , ".tmp_source.zig:1:29: error: no member named 'bogus' in '");
760792
761793
......@@ -764,11 +796,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
764796 \\ y: [get()]u8,
765797 \\};
766798 \\var global_var: usize = 1;
767 \\fn get() -> usize { global_var }
799 \\fn get() -> usize { return global_var; }
768800 \\
769 \\export fn entry() -> usize { @sizeOf(@typeOf(Foo)) }
801 \\export fn entry() -> usize { return @sizeOf(@typeOf(Foo)); }
770802 ,
771 ".tmp_source.zig:5:21: error: unable to evaluate constant expression",
803 ".tmp_source.zig:5:28: error: unable to evaluate constant expression",
772804 ".tmp_source.zig:2:12: note: called from here",
773805 ".tmp_source.zig:2:8: note: called from here");
774806
......@@ -779,7 +811,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
779811 \\};
780812 \\const x = Foo {.field = 1} + Foo {.field = 2};
781813 \\
782 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
814 \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
783815 , ".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) {
789821 \\const int_x = u32(1) / u32(0);
790822 \\const float_x = f32(1.0) / f32(0.0);
791823 \\
792 \\export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) }
793 \\export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) }
794 \\export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) }
795 \\export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) }
824 \\export fn entry1() -> usize { return @sizeOf(@typeOf(lit_int_x)); }
825 \\export fn entry2() -> usize { return @sizeOf(@typeOf(lit_float_x)); }
826 \\export fn entry3() -> usize { return @sizeOf(@typeOf(int_x)); }
827 \\export fn entry4() -> usize { return @sizeOf(@typeOf(float_x)); }
796828 ,
797829 ".tmp_source.zig:1:21: error: division by zero is undefined",
798830 ".tmp_source.zig:2:25: error: division by zero is undefined",
......@@ -804,14 +836,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
804836 \\const foo = "a
805837 \\b";
806838 \\
807 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
839 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
808840 , ".tmp_source.zig:1:13: error: newline not allowed in string literal");
809841
810842 cases.add("invalid comparison for function pointers",
811843 \\fn foo() {}
812844 \\const invalid = foo > foo;
813845 \\
814 \\export fn entry() -> usize { @sizeOf(@typeOf(invalid)) }
846 \\export fn entry() -> usize { return @sizeOf(@typeOf(invalid)); }
815847 , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'");
816848
817849 cases.add("generic function instance with non-constant expression",
......@@ -820,33 +852,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
820852 \\ return foo(a, b);
821853 \\}
822854 \\
823 \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) }
855 \\export fn entry() -> usize { return @sizeOf(@typeOf(test1)); }
824856 , ".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
846858 cases.add("assign null to non-nullable pointer",
847859 \\const a: &u8 = null;
848860 \\
849 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
861 \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
850862 , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'");
851863
852864 cases.add("indexing an array of size zero",
......@@ -859,18 +871,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
859871 cases.add("compile time division by zero",
860872 \\const y = foo(0);
861873 \\fn foo(x: u32) -> u32 {
862 \\ 1 / x
874 \\ return 1 / x;
863875 \\}
864876 \\
865 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
877 \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
866878 ,
867 ".tmp_source.zig:3:7: error: division by zero is undefined",
879 ".tmp_source.zig:3:14: error: division by zero is undefined",
868880 ".tmp_source.zig:1:14: note: called from here");
869881
870882 cases.add("branch on undefined value",
871883 \\const x = if (undefined) true else false;
872884 \\
873 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
885 \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
874886 , ".tmp_source.zig:1:15: error: use of undefined value");
875887
876888
......@@ -880,7 +892,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
880892 \\ return fibbonaci(x - 1) + fibbonaci(x - 2);
881893 \\}
882894 \\
883 \\export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) }
895 \\export fn entry() -> usize { return @sizeOf(@typeOf(seventh_fib_number)); }
884896 ,
885897 ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches",
886898 ".tmp_source.zig:3:21: note: called from here");
......@@ -888,7 +900,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
888900 cases.add("@embedFile with bogus file",
889901 \\const resource = @embedFile("bogus.txt");
890902 \\
891 \\export fn entry() -> usize { @sizeOf(@typeOf(resource)) }
903 \\export fn entry() -> usize { return @sizeOf(@typeOf(resource)); }
892904 , ".tmp_source.zig:1:29: error: unable to find '", "bogus.txt'");
893905
894906 cases.add("non-const expression in struct literal outside function",
......@@ -898,7 +910,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
898910 \\const a = Foo {.x = get_it()};
899911 \\extern fn get_it() -> i32;
900912 \\
901 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
913 \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
902914 , ".tmp_source.zig:4:21: error: unable to evaluate constant expression");
903915
904916 cases.add("non-const expression function call with struct return value outside function",
......@@ -908,11 +920,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
908920 \\const a = get_it();
909921 \\fn get_it() -> Foo {
910922 \\ global_side_effect = true;
911 \\ Foo {.x = 13}
923 \\ return Foo {.x = 13};
912924 \\}
913925 \\var global_side_effect = false;
914926 \\
915 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
927 \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
916928 ,
917929 ".tmp_source.zig:6:24: error: unable to evaluate constant expression",
918930 ".tmp_source.zig:4:17: note: called from here");
......@@ -928,21 +940,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
928940
929941 cases.add("illegal comparison of types",
930942 \\fn bad_eql_1(a: []u8, b: []u8) -> bool {
931 \\ a == b
943 \\ return a == b;
932944 \\}
933945 \\const EnumWithData = union(enum) {
934946 \\ One: void,
935947 \\ Two: i32,
936948 \\};
937949 \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool {
938 \\ *a == *b
950 \\ return *a == *b;
939951 \\}
940952 \\
941 \\export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) }
942 \\export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) }
953 \\export fn entry1() -> usize { return @sizeOf(@typeOf(bad_eql_1)); }
954 \\export fn entry2() -> usize { return @sizeOf(@typeOf(bad_eql_2)); }
943955 ,
944 ".tmp_source.zig:2:7: error: operator not allowed for type '[]u8'",
945 ".tmp_source.zig:9:8: error: operator not allowed for type 'EnumWithData'");
956 ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'",
957 ".tmp_source.zig:9:15: error: operator not allowed for type 'EnumWithData'");
946958
947959 cases.add("non-const switch number literal",
948960 \\export fn foo() {
......@@ -953,7 +965,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
953965 \\ };
954966 \\}
955967 \\fn bar() -> i32 {
956 \\ 2
968 \\ return 2;
957969 \\}
958970 , ".tmp_source.zig:2:15: error: unable to infer expression type");
959971
......@@ -976,56 +988,56 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
976988 cases.add("negation overflow in function evaluation",
977989 \\const y = neg(-128);
978990 \\fn neg(x: i8) -> i8 {
979 \\ -x
991 \\ return -x;
980992 \\}
981993 \\
982 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
994 \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
983995 ,
984 ".tmp_source.zig:3:5: error: negation caused overflow",
996 ".tmp_source.zig:3:12: error: negation caused overflow",
985997 ".tmp_source.zig:1:14: note: called from here");
986998
987999 cases.add("add overflow in function evaluation",
9881000 \\const y = add(65530, 10);
9891001 \\fn add(a: u16, b: u16) -> u16 {
990 \\ a + b
1002 \\ return a + b;
9911003 \\}
9921004 \\
993 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1005 \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
9941006 ,
995 ".tmp_source.zig:3:7: error: operation caused overflow",
1007 ".tmp_source.zig:3:14: error: operation caused overflow",
9961008 ".tmp_source.zig:1:14: note: called from here");
9971009
9981010
9991011 cases.add("sub overflow in function evaluation",
10001012 \\const y = sub(10, 20);
10011013 \\fn sub(a: u16, b: u16) -> u16 {
1002 \\ a - b
1014 \\ return a - b;
10031015 \\}
10041016 \\
1005 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1017 \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
10061018 ,
1007 ".tmp_source.zig:3:7: error: operation caused overflow",
1019 ".tmp_source.zig:3:14: error: operation caused overflow",
10081020 ".tmp_source.zig:1:14: note: called from here");
10091021
10101022 cases.add("mul overflow in function evaluation",
10111023 \\const y = mul(300, 6000);
10121024 \\fn mul(a: u16, b: u16) -> u16 {
1013 \\ a * b
1025 \\ return a * b;
10141026 \\}
10151027 \\
1016 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1028 \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
10171029 ,
1018 ".tmp_source.zig:3:7: error: operation caused overflow",
1030 ".tmp_source.zig:3:14: error: operation caused overflow",
10191031 ".tmp_source.zig:1:14: note: called from here");
10201032
10211033 cases.add("truncate sign mismatch",
10221034 \\fn f() -> i8 {
10231035 \\ const x: u32 = 10;
1024 \\ @truncate(i8, x)
1036 \\ return @truncate(i8, x);
10251037 \\}
10261038 \\
1027 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1028 , ".tmp_source.zig:3:19: error: expected signed integer type, found 'u32'");
1039 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
1040 , ".tmp_source.zig:3:26: error: expected signed integer type, found 'u32'");
10291041
10301042 cases.add("%return in function with non error return type",
10311043 \\export fn f() {
......@@ -1056,16 +1068,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
10561068
10571069 cases.add("export function with comptime parameter",
10581070 \\export fn foo(comptime x: i32, y: i32) -> i32{
1059 \\ x + y
1071 \\ return x + y;
10601072 \\}
10611073 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
10621074
10631075 cases.add("extern function with comptime parameter",
10641076 \\extern fn foo(comptime x: i32, y: i32) -> i32;
10651077 \\fn f() -> i32 {
1066 \\ foo(1, 2)
1078 \\ return foo(1, 2);
10671079 \\}
1068 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1080 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
10691081 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
10701082
10711083 cases.add("convert fixed size array to slice with invalid size",
......@@ -1079,15 +1091,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
10791091 \\var a: u32 = 0;
10801092 \\pub fn List(comptime T: type) -> type {
10811093 \\ a += 1;
1082 \\ SmallList(T, 8)
1094 \\ return SmallList(T, 8);
10831095 \\}
10841096 \\
10851097 \\pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
1086 \\ struct {
1098 \\ return struct {
10871099 \\ items: []T,
10881100 \\ length: usize,
10891101 \\ prealloc_items: [STATIC_SIZE]T,
1090 \\ }
1102 \\ };
10911103 \\}
10921104 \\
10931105 \\export fn function_with_return_type_type() {
......@@ -1102,7 +1114,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
11021114 \\fn f(m: []const u8) {
11031115 \\ m.copy(u8, self[0..], m);
11041116 \\}
1105 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1117 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
11061118 , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'");
11071119
11081120 cases.add("wrong number of arguments for method fn call",
......@@ -1113,7 +1125,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
11131125 \\
11141126 \\ foo.method(1, 2);
11151127 \\}
1116 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1128 \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
11171129 , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3");
11181130
11191131 cases.add("assign through constant pointer",
......@@ -1138,7 +1150,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
11381150 \\fn foo(blah: []u8) {
11391151 \\ for (blah) { }
11401152 \\}
1141 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1153 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
11421154 , ".tmp_source.zig:2:5: error: for loop expression missing element parameter");
11431155
11441156 cases.add("misspelled type with pointer only reference",
......@@ -1171,7 +1183,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
11711183 \\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} };
11721184 \\}
11731185 \\
1174 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1186 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
11751187 , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'");
11761188
11771189 cases.add("method call with first arg type primitive",
......@@ -1179,9 +1191,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
11791191 \\ x: i32,
11801192 \\
11811193 \\ fn init(x: i32) -> Foo {
1182 \\ Foo {
1194 \\ return Foo {
11831195 \\ .x = x,
1184 \\ }
1196 \\ };
11851197 \\ }
11861198 \\};
11871199 \\
......@@ -1198,10 +1210,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
11981210 \\ allocator: &Allocator,
11991211 \\
12001212 \\ pub fn init(allocator: &Allocator) -> List {
1201 \\ List {
1213 \\ return List {
12021214 \\ .len = 0,
12031215 \\ .allocator = allocator,
1204 \\ }
1216 \\ };
12051217 \\ }
12061218 \\};
12071219 \\
......@@ -1224,10 +1236,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
12241236 \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT;
12251237 \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1);
12261238 \\
1227 \\export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) }
1239 \\export fn entry() -> usize { return @sizeOf(@typeOf(block_aligned_stuff)); }
12281240 , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'");
12291241
1230 cases.addCase({
1242 cases.addCase(x: {
12311243 const tc = cases.create("multiple files with private function error",
12321244 \\const foo = @import("foo.zig");
12331245 \\
......@@ -1242,14 +1254,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
12421254 \\fn privateFunction() { }
12431255 );
12441256
1245 tc
1257 break :x tc;
12461258 });
12471259
12481260 cases.add("container init with non-type",
12491261 \\const zero: i32 = 0;
12501262 \\const a = zero{1};
12511263 \\
1252 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
1264 \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
12531265 , ".tmp_source.zig:2:11: error: expected type, found 'i32'");
12541266
12551267 cases.add("assign to constant field",
......@@ -1277,22 +1289,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
12771289 \\ return 0;
12781290 \\}
12791291 \\
1280 \\export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) }
1292 \\export fn entry() -> usize { return @sizeOf(@typeOf(testTrickyDefer)); }
12811293 , ".tmp_source.zig:4:11: error: cannot return from defer expression");
12821294
12831295 cases.add("attempt to access var args out of bounds",
12841296 \\fn add(args: ...) -> i32 {
1285 \\ args[0] + args[1]
1297 \\ return args[0] + args[1];
12861298 \\}
12871299 \\
12881300 \\fn foo() -> i32 {
1289 \\ add(i32(1234))
1301 \\ return add(i32(1234));
12901302 \\}
12911303 \\
1292 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1304 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
12931305 ,
1294 ".tmp_source.zig:2:19: error: index 1 outside argument list of size 1",
1295 ".tmp_source.zig:6:8: note: called from here");
1306 ".tmp_source.zig:2:26: error: index 1 outside argument list of size 1",
1307 ".tmp_source.zig:6:15: note: called from here");
12961308
12971309 cases.add("pass integer literal to var args",
12981310 \\fn add(args: ...) -> i32 {
......@@ -1304,11 +1316,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
13041316 \\}
13051317 \\
13061318 \\fn bar() -> i32 {
1307 \\ add(1, 2, 3, 4)
1319 \\ return add(1, 2, 3, 4);
13081320 \\}
13091321 \\
1310 \\export fn entry() -> usize { @sizeOf(@typeOf(bar)) }
1311 , ".tmp_source.zig:10:9: error: parameter of type '(integer literal)' requires comptime");
1322 \\export fn entry() -> usize { return @sizeOf(@typeOf(bar)); }
1323 , ".tmp_source.zig:10:16: error: parameter of type '(integer literal)' requires comptime");
13121324
13131325 cases.add("assign too big number to u16",
13141326 \\export fn foo() {
......@@ -1318,12 +1330,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
13181330
13191331 cases.add("global variable alignment non power of 2",
13201332 \\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)); }
13221334 , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2");
13231335
13241336 cases.add("function alignment non power of 2",
13251337 \\extern fn foo() align(3);
1326 \\export fn entry() { foo() }
1338 \\export fn entry() { return foo(); }
13271339 , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2");
13281340
13291341 cases.add("compile log",
......@@ -1358,7 +1370,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
13581370 \\ return *x;
13591371 \\}
13601372 \\
1361 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1373 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
13621374 , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align(1:3:6) const u3'");
13631375
13641376 cases.add("referring to a struct that is invalid",
......@@ -1394,14 +1406,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
13941406 \\export fn foo() {
13951407 \\ bar();
13961408 \\}
1397 \\fn bar() -> i32 { 0 }
1409 \\fn bar() -> i32 { return 0; }
13981410 , ".tmp_source.zig:2:8: error: expression value is ignored");
13991411
14001412 cases.add("ignored assert-err-ok return value",
14011413 \\export fn foo() {
14021414 \\ %%bar();
14031415 \\}
1404 \\fn bar() -> %i32 { 0 }
1416 \\fn bar() -> %i32 { return 0; }
14051417 , ".tmp_source.zig:2:5: error: expression value is ignored");
14061418
14071419 cases.add("ignored statement value",
......@@ -1428,11 +1440,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
14281440 \\}
14291441 , ".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",
14321444 \\export fn foo() {
14331445 \\ defer bar();
14341446 \\}
1435 \\fn bar() -> %i32 { 0 }
1447 \\fn bar() -> %i32 { return 0; }
14361448 , ".tmp_source.zig:2:14: error: expression value is ignored");
14371449
14381450 cases.add("dereference an array",
......@@ -1443,7 +1455,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
14431455 \\ return (*out)[0..1];
14441456 \\}
14451457 \\
1446 \\export fn entry() -> usize { @sizeOf(@typeOf(pass)) }
1458 \\export fn entry() -> usize { return @sizeOf(@typeOf(pass)); }
14471459 , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'");
14481460
14491461 cases.add("pass const ptr to mutable ptr fn",
......@@ -1456,10 +1468,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
14561468 \\ return true;
14571469 \\}
14581470 \\
1459 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1471 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
14601472 , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'");
14611473
1462 cases.addCase({
1474 cases.addCase(x: {
14631475 const tc = cases.create("export collision",
14641476 \\const foo = @import("foo.zig");
14651477 \\
......@@ -1468,20 +1480,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
14681480 \\}
14691481 ,
14701482 "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
14731485 tc.addSourceFile("foo.zig",
14741486 \\export fn bar() {}
14751487 \\pub const baz = 1234;
14761488 );
14771489
1478 tc
1490 break :x tc;
14791491 });
14801492
14811493 cases.add("pass non-copyable type by value to function",
14821494 \\const Point = struct { x: i32, y: i32, };
14831495 \\fn foo(p: Point) { }
1484 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1496 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
14851497 , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value");
14861498
14871499 cases.add("implicit cast from array to mutable slice",
......@@ -1504,7 +1516,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
15041516 \\fn foo(e: error) -> u2 {
15051517 \\ return u2(e);
15061518 \\}
1507 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1519 \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
15081520 , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'");
15091521
15101522 cases.add("asm at compile time",
......@@ -1611,23 +1623,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
16111623 "error: 'main' is private",
16121624 ".tmp_source.zig:1:1: note: declared here");
16131625
1614 cases.add("@setGlobalSection extern variable",
1615 \\extern var foo: i32;
1616 \\comptime {
1617 \\ @setGlobalSection(foo, ".text2");
1626 cases.add("setting a section on an extern variable",
1627 \\extern var foo: i32 section(".text2");
1628 \\export fn entry() -> i32 {
1629 \\ return foo;
16181630 \\}
16191631 ,
1620 ".tmp_source.zig:3:5: error: cannot set section of external variable 'foo'",
1621 ".tmp_source.zig:1:8: note: declared here");
1632 ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'");
16221633
1623 cases.add("@setGlobalSection extern fn",
1624 \\extern fn foo();
1625 \\comptime {
1626 \\ @setGlobalSection(foo, ".text2");
1634 cases.add("setting a section on a local variable",
1635 \\export fn entry() -> i32 {
1636 \\ var foo: i32 section(".text2") = 1234;
1637 \\ return foo;
16271638 \\}
16281639 ,
1629 ".tmp_source.zig:3:5: error: cannot set section of external function 'foo'",
1630 ".tmp_source.zig:1:8: note: declared here");
1640 ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'");
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
16321650 cases.add("returning address of local variable - simple",
16331651 \\export fn foo() -> &i32 {
......@@ -1648,17 +1666,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
16481666
16491667 cases.add("inner struct member shadowing outer struct member",
16501668 \\fn A() -> type {
1651 \\ struct {
1669 \\ return struct {
16521670 \\ b: B(),
16531671 \\
16541672 \\ const Self = this;
16551673 \\
16561674 \\ fn B() -> type {
1657 \\ struct {
1675 \\ return struct {
16581676 \\ const Self = this;
1659 \\ }
1677 \\ };
16601678 \\ }
1661 \\ }
1679 \\ };
16621680 \\}
16631681 \\comptime {
16641682 \\ assert(A().B().Self != A().Self);
......@@ -1674,7 +1692,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
16741692 \\export fn foo() {
16751693 \\ while (bar()) {}
16761694 \\}
1677 \\fn bar() -> ?i32 { 1 }
1695 \\fn bar() -> ?i32 { return 1; }
16781696 ,
16791697 ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'");
16801698
......@@ -1682,7 +1700,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
16821700 \\export fn foo() {
16831701 \\ while (bar()) {}
16841702 \\}
1685 \\fn bar() -> %i32 { 1 }
1703 \\fn bar() -> %i32 { return 1; }
16861704 ,
16871705 ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'");
16881706
......@@ -1690,7 +1708,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
16901708 \\export fn foo() {
16911709 \\ while (bar()) |x| {}
16921710 \\}
1693 \\fn bar() -> bool { true }
1711 \\fn bar() -> bool { return true; }
16941712 ,
16951713 ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'");
16961714
......@@ -1698,7 +1716,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
16981716 \\export fn foo() {
16991717 \\ while (bar()) |x| {}
17001718 \\}
1701 \\fn bar() -> %i32 { 1 }
1719 \\fn bar() -> %i32 { return 1; }
17021720 ,
17031721 ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'");
17041722
......@@ -1706,7 +1724,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
17061724 \\export fn foo() {
17071725 \\ while (bar()) |x| {} else |err| {}
17081726 \\}
1709 \\fn bar() -> bool { true }
1727 \\fn bar() -> bool { return true; }
17101728 ,
17111729 ".tmp_source.zig:2:15: error: expected error union type, found 'bool'");
17121730
......@@ -1714,7 +1732,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
17141732 \\export fn foo() {
17151733 \\ while (bar()) |x| {} else |err| {}
17161734 \\}
1717 \\fn bar() -> ?i32 { 1 }
1735 \\fn bar() -> ?i32 { return 1; }
17181736 ,
17191737 ".tmp_source.zig:2:15: error: expected error union type, found '?i32'");
17201738
......@@ -1745,17 +1763,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
17451763
17461764 cases.add("signed integer division",
17471765 \\export fn foo(a: i32, b: i32) -> i32 {
1748 \\ a / b
1766 \\ return a / b;
17491767 \\}
17501768 ,
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
17531771 cases.add("signed integer remainder division",
17541772 \\export fn foo(a: i32, b: i32) -> i32 {
1755 \\ a % b
1773 \\ return a % b;
17561774 \\}
17571775 ,
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
17601778 cases.add("cast negative value to unsigned integer",
17611779 \\comptime {
......@@ -1838,16 +1856,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
18381856 ,
18391857 ".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
18511859 cases.add("calling a var args function only known at runtime",
18521860 \\var foos = []fn(...) { foo1, foo2 };
18531861 \\
......@@ -1915,17 +1923,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
19151923
19161924 cases.add("explicit cast float literal to integer when there is a fraction component",
19171925 \\export fn entry() -> i32 {
1918 \\ i32(12.34)
1926 \\ return i32(12.34);
19191927 \\}
19201928 ,
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
19231931 cases.add("non pointer given to @ptrToInt",
19241932 \\export fn entry(x: i32) -> usize {
1925 \\ @ptrToInt(x)
1933 \\ return @ptrToInt(x);
19261934 \\}
19271935 ,
1928 ".tmp_source.zig:2:15: error: expected pointer, found 'i32'");
1936 ".tmp_source.zig:2:22: error: expected pointer, found 'i32'");
19291937
19301938 cases.add("@shlExact shifts out 1 bits",
19311939 \\comptime {
......@@ -2021,7 +2029,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
20212029
20222030 cases.add("@alignCast expects pointer or slice",
20232031 \\export fn entry() {
2024 \\ @alignCast(4, u32(3))
2032 \\ @alignCast(4, u32(3));
20252033 \\}
20262034 ,
20272035 ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'");
......@@ -2033,7 +2041,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
20332041 \\fn testImplicitlyDecreaseFnAlign(ptr: fn () align(8) -> i32, answer: i32) {
20342042 \\ if (ptr() != answer) unreachable;
20352043 \\}
2036 \\fn alignedSmall() align(4) -> i32 { 1234 }
2044 \\fn alignedSmall() align(4) -> i32 { return 1234; }
20372045 ,
20382046 ".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) {
21202128 ,
21212129 ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'");
21222130
2123 cases.add("wrong types given to setGlobalLinkage",
2124 \\export fn entry() {
2125 \\ @setGlobalLinkage(entry, u32(1234));
2131 cases.add("wrong types given to @export",
2132 \\extern fn entry() { }
2133 \\comptime {
2134 \\ @export("entry", entry, u32(1234));
21262135 \\}
21272136 ,
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
21302139 cases.add("struct with invalid field",
21312140 \\const std = @import("std");
......@@ -2198,17 +2207,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
21982207 \\const Mode = @import("builtin").Mode;
21992208 \\
22002209 \\fn Free(comptime filename: []const u8) -> TestCase {
2201 \\ TestCase {
2210 \\ return TestCase {
22022211 \\ .filename = filename,
22032212 \\ .problem_type = ProblemType.Free,
2204 \\ }
2213 \\ };
22052214 \\}
22062215 \\
22072216 \\fn LibC(comptime filename: []const u8) -> TestCase {
2208 \\ TestCase {
2217 \\ return TestCase {
22092218 \\ .filename = filename,
22102219 \\ .problem_type = ProblemType.LinkLibC,
2211 \\ }
2220 \\ };
22122221 \\}
22132222 \\
22142223 \\const TestCase = struct {
......@@ -2366,9 +2375,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
23662375 \\pub fn MemoryPool(comptime T: type) -> type {
23672376 \\ const free_list_t = @compileError("aoeu");
23682377 \\
2369 \\ struct {
2378 \\ return struct {
23702379 \\ free_list: free_list_t,
2371 \\ }
2380 \\ };
23722381 \\}
23732382 \\
23742383 \\export fn entry() {
......@@ -2643,7 +2652,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
26432652 \\ C: bool,
26442653 \\};
26452654 \\export fn entry() {
2646 \\ var a = Payload { .A = { 1234 } };
2655 \\ var a = Payload { .A = 1234 };
26472656 \\}
26482657 ,
26492658 ".tmp_source.zig:6:29: error: extern union does not support enum tag type");
......@@ -2660,7 +2669,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
26602669 \\ C: bool,
26612670 \\};
26622671 \\export fn entry() {
2663 \\ var a = Payload { .A = { 1234 } };
2672 \\ var a = Payload { .A = 1234 };
26642673 \\}
26652674 ,
26662675 ".tmp_source.zig:6:29: error: packed union does not support enum tag type");
......@@ -2672,7 +2681,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
26722681 \\ C: bool,
26732682 \\};
26742683 \\export fn entry() {
2675 \\ const a = Payload { .A = { 1234 } };
2684 \\ const a = Payload { .A = 1234 };
26762685 \\ foo(a);
26772686 \\}
26782687 \\fn foo(a: &const Payload) {
......@@ -2684,4 +2693,47 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
26842693 ,
26852694 ".tmp_source.zig:11:13: error: switch on union which has no attached enum",
26862695 ".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'");
26872739}
test/debug_safety.zig+15-15
......@@ -19,7 +19,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
1919 \\ baz(bar(a));
2020 \\}
2121 \\fn bar(a: []const i32) -> i32 {
22 \\ a[4]
22 \\ return a[4];
2323 \\}
2424 \\fn baz(a: i32) { }
2525 );
......@@ -34,7 +34,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
3434 \\ if (x == 0) return error.Whatever;
3535 \\}
3636 \\fn add(a: u16, b: u16) -> u16 {
37 \\ a + b
37 \\ return a + b;
3838 \\}
3939 );
4040
......@@ -48,7 +48,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
4848 \\ if (x == 0) return error.Whatever;
4949 \\}
5050 \\fn sub(a: u16, b: u16) -> u16 {
51 \\ a - b
51 \\ return a - b;
5252 \\}
5353 );
5454
......@@ -62,7 +62,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
6262 \\ if (x == 0) return error.Whatever;
6363 \\}
6464 \\fn mul(a: u16, b: u16) -> u16 {
65 \\ a * b
65 \\ return a * b;
6666 \\}
6767 );
6868
......@@ -76,7 +76,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
7676 \\ if (x == 32767) return error.Whatever;
7777 \\}
7878 \\fn neg(a: i16) -> i16 {
79 \\ -a
79 \\ return -a;
8080 \\}
8181 );
8282
......@@ -90,7 +90,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
9090 \\ if (x == 32767) return error.Whatever;
9191 \\}
9292 \\fn div(a: i16, b: i16) -> i16 {
93 \\ @divTrunc(a, b)
93 \\ return @divTrunc(a, b);
9494 \\}
9595 );
9696
......@@ -104,7 +104,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
104104 \\ if (x == 0) return error.Whatever;
105105 \\}
106106 \\fn shl(a: i16, b: u4) -> i16 {
107 \\ @shlExact(a, b)
107 \\ return @shlExact(a, b);
108108 \\}
109109 );
110110
......@@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
118118 \\ if (x == 0) return error.Whatever;
119119 \\}
120120 \\fn shl(a: u16, b: u4) -> u16 {
121 \\ @shlExact(a, b)
121 \\ return @shlExact(a, b);
122122 \\}
123123 );
124124
......@@ -132,7 +132,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
132132 \\ if (x == 0) return error.Whatever;
133133 \\}
134134 \\fn shr(a: i16, b: u4) -> i16 {
135 \\ @shrExact(a, b)
135 \\ return @shrExact(a, b);
136136 \\}
137137 );
138138
......@@ -146,7 +146,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
146146 \\ if (x == 0) return error.Whatever;
147147 \\}
148148 \\fn shr(a: u16, b: u4) -> u16 {
149 \\ @shrExact(a, b)
149 \\ return @shrExact(a, b);
150150 \\}
151151 );
152152
......@@ -159,7 +159,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
159159 \\ const x = div0(999, 0);
160160 \\}
161161 \\fn div0(a: i32, b: i32) -> i32 {
162 \\ @divTrunc(a, b)
162 \\ return @divTrunc(a, b);
163163 \\}
164164 );
165165
......@@ -173,7 +173,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
173173 \\ if (x == 0) return error.Whatever;
174174 \\}
175175 \\fn divExact(a: i32, b: i32) -> i32 {
176 \\ @divExact(a, b)
176 \\ return @divExact(a, b);
177177 \\}
178178 );
179179
......@@ -187,7 +187,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
187187 \\ if (x.len == 0) return error.Whatever;
188188 \\}
189189 \\fn widenSlice(slice: []align(1) const u8) -> []align(1) const i32 {
190 \\ ([]align(1) const i32)(slice)
190 \\ return ([]align(1) const i32)(slice);
191191 \\}
192192 );
193193
......@@ -201,7 +201,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
201201 \\ if (x == 0) return error.Whatever;
202202 \\}
203203 \\fn shorten_cast(x: i32) -> i8 {
204 \\ i8(x)
204 \\ return i8(x);
205205 \\}
206206 );
207207
......@@ -215,7 +215,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
215215 \\ if (x == 0) return error.Whatever;
216216 \\}
217217 \\fn unsigned_cast(x: i32) -> u32 {
218 \\ u32(x)
218 \\ return u32(x);
219219 \\}
220220 );
221221
test/standalone/pkg_import/pkg.zig+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 {
189189 expected_output: []const u8,
190190 link_libc: bool,
191191 special: Special,
192 cli_args: []const []const u8,
192193
193194 const SourceFile = struct {
194195 filename: []const u8,
......@@ -201,6 +202,10 @@ pub const CompareOutputContext = struct {
201202 .source = source,
202203 });
203204 }
205
206 pub fn setCommandLineArgs(self: &TestCase, args: []const []const u8) {
207 self.cli_args = args;
208 }
204209 };
205210
206211 const RunCompareOutputStep = struct {
......@@ -210,9 +215,11 @@ pub const CompareOutputContext = struct {
210215 name: []const u8,
211216 expected_output: []const u8,
212217 test_index: usize,
218 cli_args: []const []const u8,
213219
214220 pub fn create(context: &CompareOutputContext, exe_path: []const u8,
215 name: []const u8, expected_output: []const u8) -> &RunCompareOutputStep
221 name: []const u8, expected_output: []const u8,
222 cli_args: []const []const u8) -> &RunCompareOutputStep
216223 {
217224 const allocator = context.b.allocator;
218225 const ptr = %%allocator.create(RunCompareOutputStep);
......@@ -223,6 +230,7 @@ pub const CompareOutputContext = struct {
223230 .expected_output = expected_output,
224231 .test_index = context.test_index,
225232 .step = build.Step.init("RunCompareOutput", allocator, make),
233 .cli_args = cli_args,
226234 };
227235 context.test_index += 1;
228236 return ptr;
......@@ -233,10 +241,17 @@ pub const CompareOutputContext = struct {
233241 const b = self.context.b;
234242
235243 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
237252 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);
240255 defer child.deinit();
241256
242257 child.stdin_behavior = StdIo.Ignore;
......@@ -269,7 +284,7 @@ pub const CompareOutputContext = struct {
269284 warn("Process {} terminated unexpectedly\n", full_exe_path);
270285 return error.TestFailed;
271286 },
272 };
287 }
273288
274289
275290 if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) {
......@@ -364,6 +379,7 @@ pub const CompareOutputContext = struct {
364379 .expected_output = expected_output,
365380 .link_libc = false,
366381 .special = special,
382 .cli_args = []const []const u8{},
367383 };
368384 const root_src_name = if (special == Special.Asm) "source.s" else "source.zig";
369385 tc.addSourceFile(root_src_name, source);
......@@ -420,7 +436,7 @@ pub const CompareOutputContext = struct {
420436 }
421437
422438 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name,
423 case.expected_output);
439 case.expected_output, case.cli_args);
424440 run_and_cmp_output.step.dependOn(&exe.step);
425441
426442 self.step.dependOn(&run_and_cmp_output.step);
......@@ -447,7 +463,7 @@ pub const CompareOutputContext = struct {
447463 }
448464
449465 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);
451467 run_and_cmp_output.step.dependOn(&exe.step);
452468
453469 self.step.dependOn(&run_and_cmp_output.step);
......@@ -599,7 +615,7 @@ pub const CompileErrorContext = struct {
599615 warn("Process {} terminated unexpectedly\n", b.zig_exe);
600616 return error.TestFailed;
601617 },
602 };
618 }
603619
604620
605621 const stdout = stdout_buf.toSliceConst();
......@@ -875,7 +891,7 @@ pub const TranslateCContext = struct {
875891 warn("Compilation terminated unexpectedly\n");
876892 return error.TestFailed;
877893 },
878 };
894 }
879895
880896 const stdout = stdout_buf.toSliceConst();
881897 const stderr = stderr_buf.toSliceConst();
test/translate_c.zig+94-168
......@@ -203,13 +203,13 @@ pub fn addCases(cases: &tests.TranslateCContext) {
203203 \\pub extern var fn_ptr: ?extern fn();
204204 ,
205205 \\pub inline fn foo() {
206 \\ (??fn_ptr)()
206 \\ return (??fn_ptr)();
207207 \\}
208208 ,
209209 \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;
210210 ,
211211 \\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 {
212 \\ (??fn_ptr2)(arg0, arg1)
212 \\ return (??fn_ptr2)(arg0, arg1);
213213 \\}
214214 );
215215
......@@ -325,12 +325,12 @@ pub fn addCases(cases: &tests.TranslateCContext) {
325325 \\ return a;
326326 \\}
327327 ,
328 \\export fn foo1(_arg_a: c_uint) -> c_uint {
328 \\pub export fn foo1(_arg_a: c_uint) -> c_uint {
329329 \\ var a = _arg_a;
330330 \\ a +%= 1;
331331 \\ return a;
332332 \\}
333 \\export fn foo2(_arg_a: c_int) -> c_int {
333 \\pub export fn foo2(_arg_a: c_int) -> c_int {
334334 \\ var a = _arg_a;
335335 \\ a += 1;
336336 \\ return a;
......@@ -346,7 +346,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
346346 \\ return i;
347347 \\}
348348 ,
349 \\export fn log2(_arg_a: c_uint) -> c_int {
349 \\pub export fn log2(_arg_a: c_uint) -> c_int {
350350 \\ var a = _arg_a;
351351 \\ var i: c_int = 0;
352352 \\ while (a > c_uint(0)) {
......@@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
367367 \\ return a;
368368 \\}
369369 ,
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 {
371371 \\ if (a < b) return b;
372372 \\ if (a < b) return b else return a;
373373 \\}
......@@ -382,7 +382,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
382382 \\ return a;
383383 \\}
384384 ,
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 {
386386 \\ if (a == b) return a;
387387 \\ if (a != b) return b;
388388 \\ return a;
......@@ -407,7 +407,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
407407 \\ c = a % b;
408408 \\}
409409 ,
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 {
411411 \\ var c: c_int;
412412 \\ c = (a + b);
413413 \\ c = (a - b);
......@@ -415,7 +415,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
415415 \\ c = @divTrunc(a, b);
416416 \\ c = @rem(a, b);
417417 \\}
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 {
419419 \\ var c: c_uint;
420420 \\ c = (a +% b);
421421 \\ c = (a -% b);
......@@ -430,7 +430,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
430430 \\ return (a & b) ^ (a | b);
431431 \\}
432432 ,
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 {
434434 \\ return (a & b) ^ (a | b);
435435 \\}
436436 );
......@@ -444,7 +444,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
444444 \\ return a;
445445 \\}
446446 ,
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 {
448448 \\ if ((a < b) or (a == b)) return b;
449449 \\ if ((a >= b) and (a == b)) return a;
450450 \\ return a;
......@@ -458,7 +458,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
458458 \\ a = tmp;
459459 \\}
460460 ,
461 \\export fn max(_arg_a: c_int) -> c_int {
461 \\pub export fn max(_arg_a: c_int) -> c_int {
462462 \\ var a = _arg_a;
463463 \\ var tmp: c_int;
464464 \\ tmp = a;
......@@ -472,13 +472,13 @@ pub fn addCases(cases: &tests.TranslateCContext) {
472472 \\ c = b = a;
473473 \\}
474474 ,
475 \\export fn max(a: c_int) {
475 \\pub export fn max(a: c_int) {
476476 \\ var b: c_int;
477477 \\ var c: c_int;
478 \\ c = {
478 \\ c = x: {
479479 \\ const _tmp = a;
480480 \\ b = _tmp;
481 \\ _tmp
481 \\ break :x _tmp;
482482 \\ };
483483 \\}
484484 );
......@@ -493,7 +493,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
493493 \\ return i;
494494 \\}
495495 ,
496 \\export fn log2(_arg_a: u32) -> c_int {
496 \\pub export fn log2(_arg_a: u32) -> c_int {
497497 \\ var a = _arg_a;
498498 \\ var i: c_int = 0;
499499 \\ while (a > c_uint(0)) {
......@@ -518,7 +518,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
518518 \\void foo(void) { bar(); }
519519 ,
520520 \\pub fn bar() {}
521 \\export fn foo() {
521 \\pub export fn foo() {
522522 \\ bar();
523523 \\}
524524 );
......@@ -534,7 +534,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
534534 \\pub const struct_Foo = extern struct {
535535 \\ field: c_int,
536536 \\};
537 \\export fn read_field(foo: ?&struct_Foo) -> c_int {
537 \\pub export fn read_field(foo: ?&struct_Foo) -> c_int {
538538 \\ return (??foo).field;
539539 \\}
540540 );
......@@ -544,7 +544,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
544544 \\ ;;;;;
545545 \\}
546546 ,
547 \\export fn foo() {}
547 \\pub export fn foo() {}
548548 );
549549
550550 cases.add("undefined array global",
......@@ -560,7 +560,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
560560 \\}
561561 ,
562562 \\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 {
564564 \\ return array[index];
565565 \\}
566566 );
......@@ -571,7 +571,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
571571 \\ return (int)a;
572572 \\}
573573 ,
574 \\export fn float_to_int(a: f32) -> c_int {
574 \\pub export fn float_to_int(a: f32) -> c_int {
575575 \\ return c_int(a);
576576 \\}
577577 );
......@@ -581,7 +581,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
581581 \\ return x;
582582 \\}
583583 ,
584 \\export fn foo(x: ?&c_ushort) -> ?&c_void {
584 \\pub export fn foo(x: ?&c_ushort) -> ?&c_void {
585585 \\ return @ptrCast(?&c_void, x);
586586 \\}
587587 );
......@@ -592,7 +592,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
592592 \\ return sizeof(int);
593593 \\}
594594 ,
595 \\export fn size_of() -> usize {
595 \\pub export fn size_of() -> usize {
596596 \\ return @sizeOf(c_int);
597597 \\}
598598 );
......@@ -602,7 +602,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
602602 \\ return 0;
603603 \\}
604604 ,
605 \\export fn foo() -> ?&c_int {
605 \\pub export fn foo() -> ?&c_int {
606606 \\ return null;
607607 \\}
608608 );
......@@ -612,10 +612,10 @@ pub fn addCases(cases: &tests.TranslateCContext) {
612612 \\ return 1, 2;
613613 \\}
614614 ,
615 \\export fn foo() -> c_int {
616 \\ return {
615 \\pub export fn foo() -> c_int {
616 \\ return x: {
617617 \\ _ = 1;
618 \\ 2
618 \\ break :x 2;
619619 \\ };
620620 \\}
621621 );
......@@ -625,7 +625,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
625625 \\ return (1 << 2) >> 1;
626626 \\}
627627 ,
628 \\export fn foo() -> c_int {
628 \\pub export fn foo() -> c_int {
629629 \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1);
630630 \\}
631631 );
......@@ -643,47 +643,47 @@ pub fn addCases(cases: &tests.TranslateCContext) {
643643 \\ a <<= (a <<= 1);
644644 \\}
645645 ,
646 \\export fn foo() {
646 \\pub export fn foo() {
647647 \\ var a: c_int = 0;
648 \\ a += {
648 \\ a += x: {
649649 \\ const _ref = &a;
650650 \\ (*_ref) = ((*_ref) + 1);
651 \\ *_ref
651 \\ break :x *_ref;
652652 \\ };
653 \\ a -= {
653 \\ a -= x: {
654654 \\ const _ref = &a;
655655 \\ (*_ref) = ((*_ref) - 1);
656 \\ *_ref
656 \\ break :x *_ref;
657657 \\ };
658 \\ a *= {
658 \\ a *= x: {
659659 \\ const _ref = &a;
660660 \\ (*_ref) = ((*_ref) * 1);
661 \\ *_ref
661 \\ break :x *_ref;
662662 \\ };
663 \\ a &= {
663 \\ a &= x: {
664664 \\ const _ref = &a;
665665 \\ (*_ref) = ((*_ref) & 1);
666 \\ *_ref
666 \\ break :x *_ref;
667667 \\ };
668 \\ a |= {
668 \\ a |= x: {
669669 \\ const _ref = &a;
670670 \\ (*_ref) = ((*_ref) | 1);
671 \\ *_ref
671 \\ break :x *_ref;
672672 \\ };
673 \\ a ^= {
673 \\ a ^= x: {
674674 \\ const _ref = &a;
675675 \\ (*_ref) = ((*_ref) ^ 1);
676 \\ *_ref
676 \\ break :x *_ref;
677677 \\ };
678 \\ a >>= @import("std").math.Log2Int(c_int)({
678 \\ a >>= @import("std").math.Log2Int(c_int)(x: {
679679 \\ const _ref = &a;
680680 \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_int)(1));
681 \\ *_ref
681 \\ break :x *_ref;
682682 \\ });
683 \\ a <<= @import("std").math.Log2Int(c_int)({
683 \\ a <<= @import("std").math.Log2Int(c_int)(x: {
684684 \\ const _ref = &a;
685685 \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_int)(1));
686 \\ *_ref
686 \\ break :x *_ref;
687687 \\ });
688688 \\}
689689 );
......@@ -701,47 +701,47 @@ pub fn addCases(cases: &tests.TranslateCContext) {
701701 \\ a <<= (a <<= 1);
702702 \\}
703703 ,
704 \\export fn foo() {
704 \\pub export fn foo() {
705705 \\ var a: c_uint = c_uint(0);
706 \\ a +%= {
706 \\ a +%= x: {
707707 \\ const _ref = &a;
708708 \\ (*_ref) = ((*_ref) +% c_uint(1));
709 \\ *_ref
709 \\ break :x *_ref;
710710 \\ };
711 \\ a -%= {
711 \\ a -%= x: {
712712 \\ const _ref = &a;
713713 \\ (*_ref) = ((*_ref) -% c_uint(1));
714 \\ *_ref
714 \\ break :x *_ref;
715715 \\ };
716 \\ a *%= {
716 \\ a *%= x: {
717717 \\ const _ref = &a;
718718 \\ (*_ref) = ((*_ref) *% c_uint(1));
719 \\ *_ref
719 \\ break :x *_ref;
720720 \\ };
721 \\ a &= {
721 \\ a &= x: {
722722 \\ const _ref = &a;
723723 \\ (*_ref) = ((*_ref) & c_uint(1));
724 \\ *_ref
724 \\ break :x *_ref;
725725 \\ };
726 \\ a |= {
726 \\ a |= x: {
727727 \\ const _ref = &a;
728728 \\ (*_ref) = ((*_ref) | c_uint(1));
729 \\ *_ref
729 \\ break :x *_ref;
730730 \\ };
731 \\ a ^= {
731 \\ a ^= x: {
732732 \\ const _ref = &a;
733733 \\ (*_ref) = ((*_ref) ^ c_uint(1));
734 \\ *_ref
734 \\ break :x *_ref;
735735 \\ };
736 \\ a >>= @import("std").math.Log2Int(c_uint)({
736 \\ a >>= @import("std").math.Log2Int(c_uint)(x: {
737737 \\ const _ref = &a;
738738 \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_uint)(1));
739 \\ *_ref
739 \\ break :x *_ref;
740740 \\ });
741 \\ a <<= @import("std").math.Log2Int(c_uint)({
741 \\ a <<= @import("std").math.Log2Int(c_uint)(x: {
742742 \\ const _ref = &a;
743743 \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_uint)(1));
744 \\ *_ref
744 \\ break :x *_ref;
745745 \\ });
746746 \\}
747747 );
......@@ -771,36 +771,36 @@ pub fn addCases(cases: &tests.TranslateCContext) {
771771 \\ u = u--;
772772 \\}
773773 ,
774 \\export fn foo() {
774 \\pub export fn foo() {
775775 \\ var i: c_int = 0;
776776 \\ var u: c_uint = c_uint(0);
777777 \\ i += 1;
778778 \\ i -= 1;
779779 \\ u +%= 1;
780780 \\ u -%= 1;
781 \\ i = {
781 \\ i = x: {
782782 \\ const _ref = &i;
783783 \\ const _tmp = *_ref;
784784 \\ (*_ref) += 1;
785 \\ _tmp
785 \\ break :x _tmp;
786786 \\ };
787 \\ i = {
787 \\ i = x: {
788788 \\ const _ref = &i;
789789 \\ const _tmp = *_ref;
790790 \\ (*_ref) -= 1;
791 \\ _tmp
791 \\ break :x _tmp;
792792 \\ };
793 \\ u = {
793 \\ u = x: {
794794 \\ const _ref = &u;
795795 \\ const _tmp = *_ref;
796796 \\ (*_ref) +%= 1;
797 \\ _tmp
797 \\ break :x _tmp;
798798 \\ };
799 \\ u = {
799 \\ u = x: {
800800 \\ const _ref = &u;
801801 \\ const _tmp = *_ref;
802802 \\ (*_ref) -%= 1;
803 \\ _tmp
803 \\ break :x _tmp;
804804 \\ };
805805 \\}
806806 );
......@@ -819,32 +819,32 @@ pub fn addCases(cases: &tests.TranslateCContext) {
819819 \\ u = --u;
820820 \\}
821821 ,
822 \\export fn foo() {
822 \\pub export fn foo() {
823823 \\ var i: c_int = 0;
824824 \\ var u: c_uint = c_uint(0);
825825 \\ i += 1;
826826 \\ i -= 1;
827827 \\ u +%= 1;
828828 \\ u -%= 1;
829 \\ i = {
829 \\ i = x: {
830830 \\ const _ref = &i;
831831 \\ (*_ref) += 1;
832 \\ *_ref
832 \\ break :x *_ref;
833833 \\ };
834 \\ i = {
834 \\ i = x: {
835835 \\ const _ref = &i;
836836 \\ (*_ref) -= 1;
837 \\ *_ref
837 \\ break :x *_ref;
838838 \\ };
839 \\ u = {
839 \\ u = x: {
840840 \\ const _ref = &u;
841841 \\ (*_ref) +%= 1;
842 \\ *_ref
842 \\ break :x *_ref;
843843 \\ };
844 \\ u = {
844 \\ u = x: {
845845 \\ const _ref = &u;
846846 \\ (*_ref) -%= 1;
847 \\ *_ref
847 \\ break :x *_ref;
848848 \\ };
849849 \\}
850850 );
......@@ -862,7 +862,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
862862 \\ while (b != 0);
863863 \\}
864864 ,
865 \\export fn foo() {
865 \\pub export fn foo() {
866866 \\ var a: c_int = 2;
867867 \\ while (true) {
868868 \\ a -= 1;
......@@ -886,9 +886,9 @@ pub fn addCases(cases: &tests.TranslateCContext) {
886886 \\ baz();
887887 \\}
888888 ,
889 \\export fn foo() {}
890 \\export fn baz() {}
891 \\export fn bar() {
889 \\pub export fn foo() {}
890 \\pub export fn baz() {}
891 \\pub export fn bar() {
892892 \\ var f: ?extern fn() = foo;
893893 \\ (??f)();
894894 \\ (??f)();
......@@ -901,8 +901,8 @@ pub fn addCases(cases: &tests.TranslateCContext) {
901901 \\ *x = 1;
902902 \\}
903903 ,
904 \\export fn foo(x: ?&c_int) {
905 \\ (*(??x)) = 1;
904 \\pub export fn foo(x: ?&c_int) {
905 \\ (*??x) = 1;
906906 \\}
907907 );
908908
......@@ -930,7 +930,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
930930 \\pub fn foo() -> c_int {
931931 \\ var x: c_int = 1234;
932932 \\ var ptr: ?&c_int = &x;
933 \\ return *(??ptr);
933 \\ return *??ptr;
934934 \\}
935935 );
936936
......@@ -1005,48 +1005,6 @@ pub fn addCases(cases: &tests.TranslateCContext) {
10051005 \\}
10061006 );
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
10501008 cases.add("macros with field targets",
10511009 \\typedef unsigned int GLbitfield;
10521010 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
......@@ -1079,50 +1037,12 @@ pub fn addCases(cases: &tests.TranslateCContext) {
10791037 \\pub const glClearPFN = PFNGLCLEARPROC;
10801038 ,
10811039 \\pub inline fn glClearUnion(arg0: GLbitfield) {
1082 \\ (??glProcs.gl.Clear)(arg0)
1040 \\ return (??glProcs.gl.Clear)(arg0);
10831041 \\}
10841042 ,
10851043 \\pub const OpenGLProcs = union_OpenGLProcs;
10861044 );
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
11261046 cases.add("variable name shadowing",
11271047 \\int foo(void) {
11281048 \\ int x = 1;
......@@ -1188,4 +1108,10 @@ pub fn addCases(cases: &tests.TranslateCContext) {
11881108 \\ const v2: &const u8 = c"2.2.2";
11891109 \\}
11901110 );
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 );
11911117}