Merge remote-tracking branch 'origin/master' into llvm6
commit
e9d7623e1f
25
build.zig
25
build.zig
|
@ -1,13 +1,36 @@
|
|||
const Builder = @import("std").build.Builder;
|
||||
const tests = @import("test/tests.zig");
|
||||
const os = @import("std").os;
|
||||
|
||||
pub fn build(b: &Builder) {
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
|
||||
|
||||
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8 {
|
||||
docgen_exe.getOutputPath(),
|
||||
"doc/langref.html.in",
|
||||
%%os.path.join(b.allocator, b.cache_root, "langref.html"),
|
||||
});
|
||||
docgen_cmd.step.dependOn(&docgen_exe.step);
|
||||
|
||||
var docgen_home_cmd = b.addCommand(null, b.env_map, [][]const u8 {
|
||||
docgen_exe.getOutputPath(),
|
||||
"doc/home.html.in",
|
||||
%%os.path.join(b.allocator, b.cache_root, "home.html"),
|
||||
});
|
||||
docgen_home_cmd.step.dependOn(&docgen_exe.step);
|
||||
|
||||
const docs_step = b.step("docs", "Build documentation");
|
||||
docs_step.dependOn(&docgen_cmd.step);
|
||||
docs_step.dependOn(&docgen_home_cmd.step);
|
||||
|
||||
var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
|
||||
exe.setBuildMode(mode);
|
||||
exe.linkSystemLibrary("c");
|
||||
|
||||
b.default_step.dependOn(&exe.step);
|
||||
b.default_step.dependOn(docs_step);
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
|
@ -16,6 +39,8 @@ pub fn build(b: &Builder) {
|
|||
const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") ?? false;
|
||||
const test_step = b.step("test", "Run all the tests");
|
||||
|
||||
test_step.dependOn(docs_step);
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter,
|
||||
"test/behavior.zig", "behavior", "Run the behavior tests",
|
||||
with_lldb));
|
||||
|
|
|
@ -14,16 +14,16 @@ make install
|
|||
./zig build --build-file ../build.zig test
|
||||
|
||||
./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc
|
||||
wine test.exe
|
||||
wine zig-cache/test.exe
|
||||
|
||||
./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-fast
|
||||
wine test.exe
|
||||
wine zig-cache/test.exe
|
||||
|
||||
./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-safe
|
||||
wine test.exe
|
||||
wine zig-cache/test.exe
|
||||
|
||||
./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc
|
||||
wine64 test.exe
|
||||
wine64 zig-cache/test.exe
|
||||
|
||||
#./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc --release-fast
|
||||
#wine64 test.exe
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
const std = @import("std");
|
||||
const io = std.io;
|
||||
const os = std.os;
|
||||
|
||||
pub fn main() -> %void {
|
||||
// TODO use a more general purpose allocator here
|
||||
var inc_allocator = %%std.heap.IncrementingAllocator.init(5 * 1024 * 1024);
|
||||
defer inc_allocator.deinit();
|
||||
const allocator = &inc_allocator.allocator;
|
||||
|
||||
var args_it = os.args();
|
||||
|
||||
if (!args_it.skip()) @panic("expected self arg");
|
||||
|
||||
const in_file_name = %%(args_it.next(allocator) ?? @panic("expected input arg"));
|
||||
defer allocator.free(in_file_name);
|
||||
|
||||
const out_file_name = %%(args_it.next(allocator) ?? @panic("expected output arg"));
|
||||
defer allocator.free(out_file_name);
|
||||
|
||||
var in_file = %%io.File.openRead(in_file_name, allocator);
|
||||
defer in_file.close();
|
||||
|
||||
var out_file = %%io.File.openWrite(out_file_name, allocator);
|
||||
defer out_file.close();
|
||||
|
||||
var file_in_stream = io.FileInStream.init(&in_file);
|
||||
var buffered_in_stream = io.BufferedInStream.init(&file_in_stream.stream);
|
||||
|
||||
var file_out_stream = io.FileOutStream.init(&out_file);
|
||||
var buffered_out_stream = io.BufferedOutStream.init(&file_out_stream.stream);
|
||||
|
||||
gen(&buffered_in_stream.stream, &buffered_out_stream.stream);
|
||||
%%buffered_out_stream.flush();
|
||||
|
||||
}
|
||||
|
||||
const State = enum {
|
||||
Start,
|
||||
Derp,
|
||||
};
|
||||
|
||||
// TODO look for code segments
|
||||
|
||||
fn gen(in: &io.InStream, out: &const io.OutStream) {
|
||||
var state = State.Start;
|
||||
while (true) {
|
||||
const byte = in.readByte() %% |err| {
|
||||
if (err == error.EndOfStream) {
|
||||
return;
|
||||
}
|
||||
std.debug.panic("{}", err)
|
||||
};
|
||||
switch (state) {
|
||||
State.Start => switch (byte) {
|
||||
else => {
|
||||
%%out.writeByte(byte);
|
||||
},
|
||||
},
|
||||
State.Derp => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,719 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
||||
<title>The Zig Programming Language</title>
|
||||
<link rel="stylesheet" type="text/css" href="highlight/styles/default.css">
|
||||
<style type="text/css">
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src="zig-logo.svg">
|
||||
<p>
|
||||
Zig is an open-source programming language designed for <strong>robustness</strong>,
|
||||
<strong>optimality</strong>, and <strong>clarity</strong>.
|
||||
</p>
|
||||
<p>
|
||||
<a href="download/">Download</a> |
|
||||
<a href="documentation/master/">Documentation</a> |
|
||||
<a href="https://github.com/zig-lang/zig">Source Code</a> |
|
||||
<a href="https://github.com/zig-lang/zig/issues">Bug Tracker</a> |
|
||||
<a href="https://webchat.freenode.net/?channels=%23zig">IRC</a> |
|
||||
<a href="https://www.patreon.com/andrewrk">Donate $1/month</a>
|
||||
</p>
|
||||
<h2>Feature Highlights</h2>
|
||||
<ul>
|
||||
<li>Manual memory management. Memory allocation failure is handled correctly. Edge cases matter!</li>
|
||||
<li>Zig competes with C instead of depending on it. The Zig Standard Library does not depend on libc.</li>
|
||||
<li>Small, simple language. Focus on debugging your application rather than debugging your knowledge of your programming language.</li>
|
||||
<li>A fresh take on error handling that resembles what well-written C error handling looks like,
|
||||
minus the boilerplate and verbosity.</li>
|
||||
<li>Debug mode optimizes for fast compilation time and crashing with a stack trace when undefined behavior
|
||||
<em>would</em> happen.</li>
|
||||
<li>ReleaseFast mode produces heavily optimized code. What other projects call
|
||||
"Link Time Optimization" Zig does automatically.</li>
|
||||
<li>ReleaseSafe mode produces optimized code but keeps safety checks enabled. Disable safety checks in the bottlenecks of your code.</li>
|
||||
<li>Generic data structures and functions.</li>
|
||||
<li>Compile-time reflection and compile-time code execution.</li>
|
||||
<li>Import .h files and directly use C types, variables, and functions.</li>
|
||||
<li>Export functions, variables, and types for C code to depend on. Automatically generate .h files.</li>
|
||||
<li>Nullable type instead of null pointers.</li>
|
||||
<li>Order independent top level declarations.</li>
|
||||
<li>Friendly toward package maintainers. Reproducible build, bootstrapping process carefully documented. Issues filed by package maintainers are considered especially important.</li>
|
||||
<li>Cross-compiling is a first-class use case.</li>
|
||||
<li>No preprocessor. Instead Zig has a few carefully designed features that
|
||||
provide a way to accomplish things you might do with a preprocessor.</li>
|
||||
</ul>
|
||||
<h2 id="reading-material">Reading Material</h2>
|
||||
<ul>
|
||||
<li>2017-10-17 - <a href="download/0.1.1/release-notes.html">Zig 0.1.1 Release Notes</a></li>
|
||||
<li>2017-07-19 - <a href="http://tiehuis.github.io/iterative-replacement-of-c-with-zig">Iterative Replacement of C with Zig</a></li>
|
||||
<li>2017-02-16 - <a href="http://andrewkelley.me/post/a-better-way-to-implement-bit-fields.html">A Better Way to Implement Bit-Fields</a></li>
|
||||
<li>2017-02-13 - <a href="http://andrewkelley.me/post/zig-already-more-knowable-than-c.html">Zig: Already More Knowable Than C</a></li>
|
||||
<li>2017-01-30 - <a href="http://andrewkelley.me/post/zig-programming-language-blurs-line-compile-time-run-time.html">Zig Programming Language Blurs the Line Between Compile-Time and Run-Time</a></li>
|
||||
<li>2016-02-08 - <a href="http://andrewkelley.me/post/intro-to-zig.html">Introduction to the Zig Programming Language</a></li>
|
||||
</ul>
|
||||
<h2 id="source-examples">Source Code Examples</h2>
|
||||
<ul>
|
||||
<li><a href="#hello">Hello World</a></li>
|
||||
<li><a href="#hello_libc">Hello World with libc</a></li>
|
||||
<li><a href="#parse">Parsing Unsigned Integers</a></li>
|
||||
<li><a href="#hashmap">HashMap with Custom Allocator</a></li>
|
||||
<li><a href="#tetris">Tetris Clone</a></li>
|
||||
<li><a href="#clashos">Bare Bones Operating System</a></li>
|
||||
<li><a href="#cat">Cat Utility</a></li>
|
||||
<li><a href="#multiline-strings">Multiline String Syntax</a></li>
|
||||
<li><a href="#mersenne">Mersenne Twister Random Number Generator</a></li>
|
||||
</ul>
|
||||
<h3 id="hello">Hello World</h3>
|
||||
<pre><code class="zig">const io = @import("std").io;
|
||||
|
||||
pub fn main() -> %void {
|
||||
%return io.stdout.printf("Hello, world!\n");
|
||||
}</code></pre>
|
||||
<p>Build this with:</p>
|
||||
<pre>zig build-exe hello.zig</pre>
|
||||
<h3 id="hello_libc">Hello World with libc</h3>
|
||||
<pre><code class="zig">const c = @cImport({
|
||||
// See https://github.com/zig-lang/zig/issues/515
|
||||
@cDefine("_NO_CRT_STDIO_INLINE", "1");
|
||||
@cInclude("stdio.h");
|
||||
@cInclude("string.h");
|
||||
});
|
||||
|
||||
const msg = c"Hello, world!\n";
|
||||
|
||||
export fn main(argc: c_int, argv: &&u8) -> c_int {
|
||||
if (c.printf(msg) != c_int(c.strlen(msg)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}</code></pre>
|
||||
<p>Build this with:</p>
|
||||
<pre>zig build-exe hello.zig --library c</pre>
|
||||
<h3 id="parse">Parsing Unsigned Integers</h3>
|
||||
<pre><code class="zig">pub fn parseUnsigned(comptime T: type, buf: []u8, radix: u8) -> %T {
|
||||
var x: T = 0;
|
||||
|
||||
for (buf) |c| {
|
||||
const digit = %return charToDigit(c, radix);
|
||||
x = %return mulOverflow(T, x, radix);
|
||||
x = %return addOverflow(T, x, digit);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
error InvalidChar;
|
||||
|
||||
fn charToDigit(c: u8, radix: u8) -> %u8 {
|
||||
const value = switch (c) {
|
||||
'0' ... '9' => c - '0',
|
||||
'A' ... 'Z' => c - 'A' + 10,
|
||||
'a' ... 'z' => c - 'a' + 10,
|
||||
else => return error.InvalidChar,
|
||||
};
|
||||
|
||||
if (value >= radix)
|
||||
return error.InvalidChar;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
error Overflow;
|
||||
|
||||
pub fn mulOverflow(comptime T: type, a: T, b: T) -> %T {
|
||||
var answer: T = undefined;
|
||||
if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer
|
||||
}
|
||||
|
||||
pub fn addOverflow(comptime T: type, a: T, b: T) -> %T {
|
||||
var answer: T = undefined;
|
||||
if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer
|
||||
}
|
||||
|
||||
fn getNumberWithDefault(s: []u8) -> u32 {
|
||||
parseUnsigned(u32, s, 10) %% 42
|
||||
}
|
||||
|
||||
fn getNumberOrCrash(s: []u8) -> u32 {
|
||||
%%parseUnsigned(u32, s, 10)
|
||||
}
|
||||
|
||||
fn addTwoTogetherOrReturnErr(a_str: []u8, b_str: []u8) -> %u32 {
|
||||
const a = parseUnsigned(u32, a_str, 10) %% |err| return err;
|
||||
const b = parseUnsigned(u32, b_str, 10) %% |err| return err;
|
||||
return a + b;
|
||||
}</code></pre>
|
||||
<h3 id="hashmap">HashMap with Custom Allocator</h3>
|
||||
<pre><code class="zig">const debug = @import("debug.zig");
|
||||
const assert = debug.assert;
|
||||
const math = @import("math.zig");
|
||||
const mem = @import("mem.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
const want_modification_safety = !@compileVar("is_release");
|
||||
const debug_u32 = if (want_modification_safety) u32 else void;
|
||||
|
||||
pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn(key: K)->u32,
|
||||
comptime eql: fn(a: K, b: K)->bool) -> type
|
||||
{
|
||||
struct {
|
||||
entries: []Entry,
|
||||
size: usize,
|
||||
max_distance_from_start_index: usize,
|
||||
allocator: &Allocator,
|
||||
// this is used to detect bugs where a hashtable is edited while an iterator is running.
|
||||
modification_count: debug_u32,
|
||||
|
||||
const Self = this;
|
||||
|
||||
pub const Entry = struct {
|
||||
used: bool,
|
||||
distance_from_start_index: usize,
|
||||
key: K,
|
||||
value: V,
|
||||
};
|
||||
|
||||
pub const Iterator = struct {
|
||||
hm: &Self,
|
||||
// how many items have we returned
|
||||
count: usize,
|
||||
// iterator through the entry array
|
||||
index: usize,
|
||||
// used to detect concurrent modification
|
||||
initial_modification_count: debug_u32,
|
||||
|
||||
pub fn next(it: &Iterator) -> ?&Entry {
|
||||
if (want_modification_safety) {
|
||||
assert(it.initial_modification_count == it.hm.modification_count); // concurrent modification
|
||||
}
|
||||
if (it.count >= it.hm.size) return null;
|
||||
while (it.index < it.hm.entries.len) : (it.index += 1) {
|
||||
const entry = &it.hm.entries[it.index];
|
||||
if (entry.used) {
|
||||
it.index += 1;
|
||||
it.count += 1;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
unreachable // no next item
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init(hm: &Self, allocator: &Allocator) {
|
||||
hm.entries = []Entry{};
|
||||
hm.allocator = allocator;
|
||||
hm.size = 0;
|
||||
hm.max_distance_from_start_index = 0;
|
||||
// it doesn't actually matter what we set this to since we use wrapping integer arithmetic
|
||||
hm.modification_count = undefined;
|
||||
}
|
||||
|
||||
pub fn deinit(hm: &Self) {
|
||||
hm.allocator.free(Entry, hm.entries);
|
||||
}
|
||||
|
||||
pub fn clear(hm: &Self) {
|
||||
for (hm.entries) |*entry| {
|
||||
entry.used = false;
|
||||
}
|
||||
hm.size = 0;
|
||||
hm.max_distance_from_start_index = 0;
|
||||
hm.incrementModificationCount();
|
||||
}
|
||||
|
||||
pub fn put(hm: &Self, key: K, value: V) -> %void {
|
||||
if (hm.entries.len == 0) {
|
||||
%return hm.initCapacity(16);
|
||||
}
|
||||
hm.incrementModificationCount();
|
||||
|
||||
// if we get too full (60%), double the capacity
|
||||
if (hm.size * 5 >= hm.entries.len * 3) {
|
||||
const old_entries = hm.entries;
|
||||
%return hm.initCapacity(hm.entries.len * 2);
|
||||
// dump all of the old elements into the new table
|
||||
for (old_entries) |*old_entry| {
|
||||
if (old_entry.used) {
|
||||
hm.internalPut(old_entry.key, old_entry.value);
|
||||
}
|
||||
}
|
||||
hm.allocator.free(Entry, old_entries);
|
||||
}
|
||||
|
||||
hm.internalPut(key, value);
|
||||
}
|
||||
|
||||
pub fn get(hm: &Self, key: K) -> ?&Entry {
|
||||
return hm.internalGet(key);
|
||||
}
|
||||
|
||||
pub fn remove(hm: &Self, key: K) {
|
||||
hm.incrementModificationCount();
|
||||
const start_index = hm.keyToIndex(key);
|
||||
{var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
|
||||
const index = (start_index + roll_over) % hm.entries.len;
|
||||
var entry = &hm.entries[index];
|
||||
|
||||
assert(entry.used); // key not found
|
||||
|
||||
if (!eql(entry.key, key)) continue;
|
||||
|
||||
while (roll_over < hm.entries.len) : (roll_over += 1) {
|
||||
const next_index = (start_index + roll_over + 1) % hm.entries.len;
|
||||
const next_entry = &hm.entries[next_index];
|
||||
if (!next_entry.used or next_entry.distance_from_start_index == 0) {
|
||||
entry.used = false;
|
||||
hm.size -= 1;
|
||||
return;
|
||||
}
|
||||
*entry = *next_entry;
|
||||
entry.distance_from_start_index -= 1;
|
||||
entry = next_entry;
|
||||
}
|
||||
unreachable // shifting everything in the table
|
||||
}}
|
||||
unreachable // key not found
|
||||
}
|
||||
|
||||
pub fn entryIterator(hm: &Self) -> Iterator {
|
||||
return Iterator {
|
||||
.hm = hm,
|
||||
.count = 0,
|
||||
.index = 0,
|
||||
.initial_modification_count = hm.modification_count,
|
||||
};
|
||||
}
|
||||
|
||||
fn initCapacity(hm: &Self, capacity: usize) -> %void {
|
||||
hm.entries = %return hm.allocator.alloc(Entry, capacity);
|
||||
hm.size = 0;
|
||||
hm.max_distance_from_start_index = 0;
|
||||
for (hm.entries) |*entry| {
|
||||
entry.used = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn incrementModificationCount(hm: &Self) {
|
||||
if (want_modification_safety) {
|
||||
hm.modification_count +%= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn internalPut(hm: &Self, orig_key: K, orig_value: V) {
|
||||
var key = orig_key;
|
||||
var value = orig_value;
|
||||
const start_index = hm.keyToIndex(key);
|
||||
var roll_over: usize = 0;
|
||||
var distance_from_start_index: usize = 0;
|
||||
while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1}) {
|
||||
const index = (start_index + roll_over) % hm.entries.len;
|
||||
const entry = &hm.entries[index];
|
||||
|
||||
if (entry.used and !eql(entry.key, key)) {
|
||||
if (entry.distance_from_start_index < distance_from_start_index) {
|
||||
// robin hood to the rescue
|
||||
const tmp = *entry;
|
||||
hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index,
|
||||
distance_from_start_index);
|
||||
*entry = Entry {
|
||||
.used = true,
|
||||
.distance_from_start_index = distance_from_start_index,
|
||||
.key = key,
|
||||
.value = value,
|
||||
};
|
||||
key = tmp.key;
|
||||
value = tmp.value;
|
||||
distance_from_start_index = tmp.distance_from_start_index;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!entry.used) {
|
||||
// adding an entry. otherwise overwriting old value with
|
||||
// same key
|
||||
hm.size += 1;
|
||||
}
|
||||
|
||||
hm.max_distance_from_start_index = math.max(distance_from_start_index, hm.max_distance_from_start_index);
|
||||
*entry = Entry {
|
||||
.used = true,
|
||||
.distance_from_start_index = distance_from_start_index,
|
||||
.key = key,
|
||||
.value = value,
|
||||
};
|
||||
return;
|
||||
}
|
||||
unreachable // put into a full map
|
||||
}
|
||||
|
||||
fn internalGet(hm: &Self, key: K) -> ?&Entry {
|
||||
const start_index = hm.keyToIndex(key);
|
||||
{var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
|
||||
const index = (start_index + roll_over) % hm.entries.len;
|
||||
const entry = &hm.entries[index];
|
||||
|
||||
if (!entry.used) return null;
|
||||
if (eql(entry.key, key)) return entry;
|
||||
}}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn keyToIndex(hm: &Self, key: K) -> usize {
|
||||
return usize(hash(key)) % hm.entries.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "basic hash map test" {
|
||||
var map: HashMap(i32, i32, hash_i32, eql_i32) = undefined;
|
||||
map.init(&debug.global_allocator);
|
||||
defer map.deinit();
|
||||
|
||||
%%map.put(1, 11);
|
||||
%%map.put(2, 22);
|
||||
%%map.put(3, 33);
|
||||
%%map.put(4, 44);
|
||||
%%map.put(5, 55);
|
||||
|
||||
assert((??map.get(2)).value == 22);
|
||||
map.remove(2);
|
||||
assert(if (const entry ?= map.get(2)) false else true);
|
||||
}
|
||||
|
||||
fn hash_i32(x: i32) -> u32 {
|
||||
*(&u32)(&x)
|
||||
}
|
||||
fn eql_i32(a: i32, b: i32) -> bool {
|
||||
a == b
|
||||
}</code></pre>
|
||||
<h3 id="tetris">Tetris Clone</h3>
|
||||
<img src="tetris-screenshot.png">
|
||||
<p>
|
||||
<a href="https://github.com/andrewrk/tetris">Source Code on GitHub</a>
|
||||
</p>
|
||||
<h3 id="clashos">Bare Bones Operating System</h3>
|
||||
<p>
|
||||
<a href="https://github.com/andrewrk/clashos">Source Code on GitHub</a>
|
||||
</p>
|
||||
<h3 id="cat">Cat Utility</h3>
|
||||
<pre><code class="zig">const std = @import("std");
|
||||
const io = std.io;
|
||||
const mem = std.mem;
|
||||
const os = std.os;
|
||||
|
||||
pub fn main() -> %void {
|
||||
const exe = os.args.at(0);
|
||||
var catted_anything = false;
|
||||
var arg_i: usize = 1;
|
||||
while (arg_i < os.args.count()) : (arg_i += 1) {
|
||||
const arg = os.args.at(arg_i);
|
||||
if (mem.eql(u8, arg, "-")) {
|
||||
catted_anything = true;
|
||||
%return cat_stream(&io.stdin);
|
||||
} else if (arg[0] == '-') {
|
||||
return usage(exe);
|
||||
} else {
|
||||
var is = io.InStream.open(arg, null) %% |err| {
|
||||
%%io.stderr.printf("Unable to open file: {}\n", @errorName(err));
|
||||
return err;
|
||||
};
|
||||
defer is.close();
|
||||
|
||||
catted_anything = true;
|
||||
%return cat_stream(&is);
|
||||
}
|
||||
}
|
||||
if (!catted_anything) {
|
||||
%return cat_stream(&io.stdin);
|
||||
}
|
||||
%return io.stdout.flush();
|
||||
}
|
||||
|
||||
fn usage(exe: []const u8) -> %void {
|
||||
%%io.stderr.printf("Usage: {} [FILE]...\n", exe);
|
||||
return error.Invalid;
|
||||
}
|
||||
|
||||
fn cat_stream(is: &io.InStream) -> %void {
|
||||
var buf: [1024 * 4]u8 = undefined;
|
||||
|
||||
while (true) {
|
||||
const bytes_read = is.read(buf[0..]) %% |err| {
|
||||
%%io.stderr.printf("Unable to read from stream: {}\n", @errorName(err));
|
||||
return err;
|
||||
};
|
||||
|
||||
if (bytes_read == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
io.stdout.write(buf[0..bytes_read]) %% |err| {
|
||||
%%io.stderr.printf("Unable to write to stdout: {}\n", @errorName(err));
|
||||
return err;
|
||||
};
|
||||
}
|
||||
}</code></pre>
|
||||
<h3 id="multiline-strings">Multiline String Syntax</h3>
|
||||
<pre><code class="zig">pub fn createAllShaders() -> AllShaders {
|
||||
var as : AllShaders = undefined;
|
||||
|
||||
as.primitive = createShader(
|
||||
\\#version 150 core
|
||||
\\
|
||||
\\in vec3 VertexPosition;
|
||||
\\
|
||||
\\uniform mat4 MVP;
|
||||
\\
|
||||
\\void main(void) {
|
||||
\\ gl_Position = vec4(VertexPosition, 1.0) * MVP;
|
||||
\\}
|
||||
,
|
||||
\\#version 150 core
|
||||
\\
|
||||
\\out vec4 FragColor;
|
||||
\\
|
||||
\\uniform vec4 Color;
|
||||
\\
|
||||
\\void main(void) {
|
||||
\\ FragColor = Color;
|
||||
\\}
|
||||
, null);
|
||||
|
||||
as.primitive_attrib_position = as.primitive.attrib_location(c"VertexPosition");
|
||||
as.primitive_uniform_mvp = as.primitive.uniform_location(c"MVP");
|
||||
as.primitive_uniform_color = as.primitive.uniform_location(c"Color");
|
||||
|
||||
|
||||
|
||||
as.texture = createShader(
|
||||
\\#version 150 core
|
||||
\\
|
||||
\\in vec3 VertexPosition;
|
||||
\\in vec2 TexCoord;
|
||||
\\
|
||||
\\out vec2 FragTexCoord;
|
||||
\\
|
||||
\\uniform mat4 MVP;
|
||||
\\
|
||||
\\void main(void)
|
||||
\\{
|
||||
\\ FragTexCoord = TexCoord;
|
||||
\\ gl_Position = vec4(VertexPosition, 1.0) * MVP;
|
||||
\\}
|
||||
,
|
||||
\\#version 150 core
|
||||
\\
|
||||
\\in vec2 FragTexCoord;
|
||||
\\out vec4 FragColor;
|
||||
\\
|
||||
\\uniform sampler2D Tex;
|
||||
\\
|
||||
\\void main(void)
|
||||
\\{
|
||||
\\ FragColor = texture(Tex, FragTexCoord);
|
||||
\\}
|
||||
, null);
|
||||
|
||||
as.texture_attrib_tex_coord = as.texture.attrib_location(c"TexCoord");
|
||||
as.texture_attrib_position = as.texture.attrib_location(c"VertexPosition");
|
||||
as.texture_uniform_mvp = as.texture.uniform_location(c"MVP");
|
||||
as.texture_uniform_tex = as.texture.uniform_location(c"Tex");
|
||||
|
||||
debug_gl.assert_no_error();
|
||||
|
||||
return as;
|
||||
}</code></pre>
|
||||
<h3 id="mersenne">Mersenne Twister Random Number Generator</h3>
|
||||
<pre><code class="zig">const assert = @import("debug.zig").assert;
|
||||
const rand_test = @import("rand_test.zig");
|
||||
|
||||
pub const MT19937_32 = MersenneTwister(
|
||||
u32, 624, 397, 31,
|
||||
0x9908B0DF,
|
||||
11, 0xFFFFFFFF,
|
||||
7, 0x9D2C5680,
|
||||
15, 0xEFC60000,
|
||||
18, 1812433253);
|
||||
|
||||
pub const MT19937_64 = MersenneTwister(
|
||||
u64, 312, 156, 31,
|
||||
0xB5026F5AA96619E9,
|
||||
29, 0x5555555555555555,
|
||||
17, 0x71D67FFFEDA60000,
|
||||
37, 0xFFF7EEE000000000,
|
||||
43, 6364136223846793005);
|
||||
|
||||
/// Use `init` to initialize this state.
|
||||
pub const Rand = struct {
|
||||
const Rng = if (@sizeOf(usize) >= 8) MT19937_64 else MT19937_32;
|
||||
|
||||
rng: Rng,
|
||||
|
||||
/// Initialize random state with the given seed.
|
||||
pub fn init(r: &Rand, seed: usize) {
|
||||
r.rng.init(seed);
|
||||
}
|
||||
|
||||
/// Get an integer with random bits.
|
||||
pub fn scalar(r: &Rand, comptime T: type) -> T {
|
||||
if (T == usize) {
|
||||
return r.rng.get();
|
||||
} else {
|
||||
var result: [@sizeOf(T)]u8 = undefined;
|
||||
r.fillBytes(result);
|
||||
return ([]T)(result)[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill `buf` with randomness.
|
||||
pub fn fillBytes(r: &Rand, buf: []u8) {
|
||||
var bytes_left = buf.len;
|
||||
while (bytes_left >= @sizeOf(usize)) {
|
||||
([]usize)(buf[buf.len - bytes_left...])[0] = r.rng.get();
|
||||
bytes_left -= @sizeOf(usize);
|
||||
}
|
||||
if (bytes_left > 0) {
|
||||
var rand_val_array : [@sizeOf(usize)]u8 = undefined;
|
||||
([]usize)(rand_val_array)[0] = r.rng.get();
|
||||
while (bytes_left > 0) {
|
||||
buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left];
|
||||
bytes_left -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a random unsigned integer with even distribution between `start`
|
||||
/// inclusive and `end` exclusive.
|
||||
// TODO support signed integers and then rename to "range"
|
||||
pub fn rangeUnsigned(r: &Rand, comptime T: type, start: T, end: T) -> T {
|
||||
const range = end - start;
|
||||
const leftover = @maxValue(T) % range;
|
||||
const upper_bound = @maxValue(T) - leftover;
|
||||
var rand_val_array : [@sizeOf(T)]u8 = undefined;
|
||||
|
||||
while (true) {
|
||||
r.fillBytes(rand_val_array);
|
||||
const rand_val = ([]T)(rand_val_array)[0];
|
||||
if (rand_val < upper_bound) {
|
||||
return start + (rand_val % range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a floating point value in the range 0.0..1.0.
|
||||
pub fn float(r: &Rand, comptime T: type) -> T {
|
||||
// TODO Implement this way instead:
|
||||
// const int = @int_type(false, @sizeOf(T) * 8);
|
||||
// const mask = ((1 << @float_mantissa_bit_count(T)) - 1);
|
||||
// const rand_bits = r.rng.scalar(int) & mask;
|
||||
// return @float_compose(T, false, 0, rand_bits) - 1.0
|
||||
const int_type = @intType(false, @sizeOf(T) * 8);
|
||||
const precision = if (T == f32) {
|
||||
16777216
|
||||
} else if (T == f64) {
|
||||
9007199254740992
|
||||
} else {
|
||||
@compileError("unknown floating point type")
|
||||
};
|
||||
return T(r.rangeUnsigned(int_type, 0, precision)) / T(precision);
|
||||
}
|
||||
};
|
||||
|
||||
fn MersenneTwister(
|
||||
comptime int: type, comptime n: usize, comptime m: usize, comptime r: int,
|
||||
comptime a: int,
|
||||
comptime u: int, comptime d: int,
|
||||
comptime s: int, comptime b: int,
|
||||
comptime t: int, comptime c: int,
|
||||
comptime l: int, comptime f: int) -> type
|
||||
{
|
||||
struct {
|
||||
const Self = this;
|
||||
|
||||
array: [n]int,
|
||||
index: usize,
|
||||
|
||||
pub fn init(mt: &Self, seed: int) {
|
||||
mt.index = n;
|
||||
|
||||
var prev_value = seed;
|
||||
mt.array[0] = prev_value;
|
||||
{var i: usize = 1; while (i < n) : (i += 1) {
|
||||
prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2)));
|
||||
mt.array[i] = prev_value;
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn get(mt: &Self) -> int {
|
||||
const mag01 = []int{0, a};
|
||||
const LM: int = (1 << r) - 1;
|
||||
const UM = ~LM;
|
||||
|
||||
if (mt.index >= n) {
|
||||
var i: usize = 0;
|
||||
|
||||
while (i < n - m) : (i += 1) {
|
||||
const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
|
||||
mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[x & 0x1];
|
||||
}
|
||||
|
||||
while (i < n - 1) : (i += 1) {
|
||||
const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
|
||||
mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[x & 0x1];
|
||||
|
||||
}
|
||||
const x = (mt.array[i] & UM) | (mt.array[0] & LM);
|
||||
mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[x & 0x1];
|
||||
|
||||
mt.index = 0;
|
||||
}
|
||||
|
||||
var x = mt.array[mt.index];
|
||||
mt.index += 1;
|
||||
|
||||
x ^= ((x >> u) & d);
|
||||
x ^= ((x <<% s) & b);
|
||||
x ^= ((x <<% t) & c);
|
||||
x ^= (x >> l);
|
||||
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "float 32" {
|
||||
var r: Rand = undefined;
|
||||
r.init(42);
|
||||
|
||||
{var i: usize = 0; while (i < 1000) : (i += 1) {
|
||||
const val = r.float(f32);
|
||||
assert(val >= 0.0);
|
||||
assert(val < 1.0);
|
||||
}}
|
||||
}
|
||||
|
||||
test "MT19937_64" {
|
||||
var rng: MT19937_64 = undefined;
|
||||
rng.init(rand_test.mt64_seed);
|
||||
for (rand_test.mt64_data) |value| {
|
||||
assert(value == rng.get());
|
||||
}
|
||||
}
|
||||
|
||||
test "MT19937_32" {
|
||||
var rng: MT19937_32 = undefined;
|
||||
rng.init(rand_test.mt32_seed);
|
||||
for (rand_test.mt32_data) |value| {
|
||||
assert(value == rng.get());
|
||||
}
|
||||
}</code></pre>
|
||||
<script src="highlight/highlight.pack.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad();</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -10,14 +10,13 @@ pub fn main() -> %void {
|
|||
const exe = %return unwrapArg(??args_it.next(allocator));
|
||||
var catted_anything = false;
|
||||
var stdout_file = %return io.getStdOut();
|
||||
const stdout = &stdout_file.out_stream;
|
||||
|
||||
while (args_it.next(allocator)) |arg_or_err| {
|
||||
const arg = %return unwrapArg(arg_or_err);
|
||||
if (mem.eql(u8, arg, "-")) {
|
||||
catted_anything = true;
|
||||
var stdin_file = %return io.getStdIn();
|
||||
%return cat_stream(stdout, &stdin_file.in_stream);
|
||||
%return cat_file(&stdout_file, &stdin_file);
|
||||
} else if (arg[0] == '-') {
|
||||
return usage(exe);
|
||||
} else {
|
||||
|
@ -28,12 +27,12 @@ pub fn main() -> %void {
|
|||
defer file.close();
|
||||
|
||||
catted_anything = true;
|
||||
%return cat_stream(stdout, &file.in_stream);
|
||||
%return cat_file(&stdout_file, &file);
|
||||
}
|
||||
}
|
||||
if (!catted_anything) {
|
||||
var stdin_file = %return io.getStdIn();
|
||||
%return cat_stream(stdout, &stdin_file.in_stream);
|
||||
%return cat_file(&stdout_file, &stdin_file);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,11 +41,11 @@ fn usage(exe: []const u8) -> %void {
|
|||
return error.Invalid;
|
||||
}
|
||||
|
||||
fn cat_stream(stdout: &io.OutStream, is: &io.InStream) -> %void {
|
||||
fn cat_file(stdout: &io.File, file: &io.File) -> %void {
|
||||
var buf: [1024 * 4]u8 = undefined;
|
||||
|
||||
while (true) {
|
||||
const bytes_read = is.read(buf[0..]) %% |err| {
|
||||
const bytes_read = file.read(buf[0..]) %% |err| {
|
||||
warn("Unable to read from stream: {}\n", @errorName(err));
|
||||
return err;
|
||||
};
|
||||
|
|
|
@ -6,10 +6,10 @@ const os = std.os;
|
|||
|
||||
pub fn main() -> %void {
|
||||
var stdout_file = %return io.getStdOut();
|
||||
const stdout = &stdout_file.out_stream;
|
||||
var stdout_file_stream = io.FileOutStream.init(&stdout_file);
|
||||
const stdout = &stdout_file_stream.stream;
|
||||
|
||||
var stdin_file = %return io.getStdIn();
|
||||
const stdin = &stdin_file.in_stream;
|
||||
|
||||
%return stdout.print("Welcome to the Guess Number Game in Zig.\n");
|
||||
|
||||
|
@ -24,7 +24,7 @@ pub fn main() -> %void {
|
|||
%return stdout.print("\nGuess a number between 1 and 100: ");
|
||||
var line_buf : [20]u8 = undefined;
|
||||
|
||||
const line_len = stdin.read(line_buf[0..]) %% |err| {
|
||||
const line_len = stdin_file.read(line_buf[0..]) %% |err| {
|
||||
%return stdout.print("Unable to read from stdin: {}\n", @errorName(err));
|
||||
return err;
|
||||
};
|
||||
|
|
|
@ -3,8 +3,7 @@ const std = @import("std");
|
|||
pub fn main() -> %void {
|
||||
// If this program is run without stdout attached, exit with an error.
|
||||
var stdout_file = %return std.io.getStdOut();
|
||||
const stdout = &stdout_file.out_stream;
|
||||
// If this program encounters pipe failure when printing to stdout, exit
|
||||
// with an error.
|
||||
%return stdout.print("Hello, world!\n");
|
||||
%return stdout_file.write("Hello, world!\n");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const builtin = @import("builtin");
|
||||
const io = @import("std").io;
|
||||
const os = @import("std").os;
|
||||
const heap = @import("std").mem;
|
||||
const heap = @import("std").heap;
|
||||
|
||||
// TODO: sync up CLI with c++ code
|
||||
// TODO: concurrency
|
||||
|
|
|
@ -1389,7 +1389,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
|||
return;
|
||||
}
|
||||
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
|
||||
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
|
||||
enum_type->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
|
|
|
@ -2666,9 +2666,16 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable
|
|||
if (ir_want_debug_safety(g, &instruction->base)) {
|
||||
TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type;
|
||||
size_t field_count = enum_type->data.enumeration.src_field_count;
|
||||
LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(enum_tag_value));
|
||||
LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false);
|
||||
add_bounds_check(g, enum_tag_value, LLVMIntUGE, zero, LLVMIntULT, end_val);
|
||||
|
||||
// if the field_count can't fit in the bits of the enum_tag_type, then it can't possibly
|
||||
// be the wrong value
|
||||
BigInt field_bi;
|
||||
bigint_init_unsigned(&field_bi, field_count);
|
||||
TypeTableEntry *tag_int_type = enum_tag_type->data.enum_tag.int_type;
|
||||
if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) {
|
||||
LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false);
|
||||
add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val);
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef indices[] = {
|
||||
|
|
12
src/ir.cpp
12
src/ir.cpp
|
@ -10311,8 +10311,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
|||
{
|
||||
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
|
||||
size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0;
|
||||
size_t var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0;
|
||||
|
||||
// for extern functions, the var args argument is not counted.
|
||||
// for zig functions, it is.
|
||||
size_t var_args_1_or_0;
|
||||
if (fn_type_id->cc == CallingConventionUnspecified) {
|
||||
var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0;
|
||||
} else {
|
||||
var_args_1_or_0 = 0;
|
||||
}
|
||||
size_t src_param_count = fn_type_id->param_count - var_args_1_or_0;
|
||||
|
||||
size_t call_param_count = call_instruction->arg_count + first_arg_1_or_0;
|
||||
AstNode *source_node = call_instruction->base.source_node;
|
||||
|
||||
|
@ -12823,6 +12832,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
|||
case TypeTableEntryIdEnum:
|
||||
{
|
||||
TypeTableEntry *tag_type = target_type->data.enumeration.tag_type;
|
||||
assert(tag_type != nullptr);
|
||||
if (pointee_val) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
|
||||
bigint_init_unsigned(&out_val->data.x_bigint, pointee_val->data.x_enum.tag);
|
||||
|
|
108
src/main.cpp
108
src/main.cpp
|
@ -20,70 +20,70 @@ static int usage(const char *arg0) {
|
|||
fprintf(stderr, "Usage: %s [command] [options]\n"
|
||||
"Commands:\n"
|
||||
" build build project from build.zig\n"
|
||||
" build-exe $source create executable from source or object files\n"
|
||||
" build-lib $source create library from source or object files\n"
|
||||
" build-obj $source create object from source or assembly\n"
|
||||
" parsec $source convert c code to zig code\n"
|
||||
" build-exe [source] create executable from source or object files\n"
|
||||
" build-lib [source] create library from source or object files\n"
|
||||
" build-obj [source] create object from source or assembly\n"
|
||||
" parsec [source] convert c code to zig code\n"
|
||||
" targets list available compilation targets\n"
|
||||
" test $source create and run a test build\n"
|
||||
" test [source] create and run a test build\n"
|
||||
" version print version number and exit\n"
|
||||
" zen print zen of zig and exit\n"
|
||||
"Compile Options:\n"
|
||||
" --assembly $source add assembly file to build\n"
|
||||
" --cache-dir $path override the cache directory\n"
|
||||
" --color $auto|off|on enable or disable colored error messages\n"
|
||||
" --emit $filetype emit a specific file format as compilation output\n"
|
||||
" --assembly [source] add assembly file to build\n"
|
||||
" --cache-dir [path] override the cache directory\n"
|
||||
" --color [auto|off|on] enable or disable colored error messages\n"
|
||||
" --emit [filetype] emit a specific file format as compilation output\n"
|
||||
" --enable-timing-info print timing diagnostics\n"
|
||||
" --libc-include-dir $path directory where libc stdlib.h resides\n"
|
||||
" --name $name override output name\n"
|
||||
" --output $file override destination path\n"
|
||||
" --output-h $file override generated header file path\n"
|
||||
" --pkg-begin $name $path make package available to import and push current pkg\n"
|
||||
" --libc-include-dir [path] directory where libc stdlib.h resides\n"
|
||||
" --name [name] override output name\n"
|
||||
" --output [file] override destination path\n"
|
||||
" --output-h [file] override generated header file path\n"
|
||||
" --pkg-begin [name] [path] make package available to import and push current pkg\n"
|
||||
" --pkg-end pop current pkg\n"
|
||||
" --release-fast build with optimizations on and safety off\n"
|
||||
" --release-safe build with optimizations on and safety on\n"
|
||||
" --static output will be statically linked\n"
|
||||
" --strip exclude debug symbols\n"
|
||||
" --target-arch $name specify target architecture\n"
|
||||
" --target-environ $name specify target environment\n"
|
||||
" --target-os $name specify target operating system\n"
|
||||
" --target-arch [name] specify target architecture\n"
|
||||
" --target-environ [name] specify target environment\n"
|
||||
" --target-os [name] specify target operating system\n"
|
||||
" --verbose-tokenize turn on compiler debug output for tokenization\n"
|
||||
" --verbose-ast turn on compiler debug output for parsing into an AST\n"
|
||||
" --verbose-link turn on compiler debug output for linking\n"
|
||||
" --verbose-ir turn on compiler debug output for Zig IR\n"
|
||||
" --verbose-llvm-ir turn on compiler debug output for LLVM IR\n"
|
||||
" --verbose-cimport turn on compiler debug output for C imports\n"
|
||||
" --zig-install-prefix $path override directory where zig thinks it is installed\n"
|
||||
" -dirafter $dir same as -isystem but do it last\n"
|
||||
" -isystem $dir add additional search path for other .h files\n"
|
||||
" -mllvm $arg additional arguments to forward to LLVM's option processing\n"
|
||||
" --zig-install-prefix [path] override directory where zig thinks it is installed\n"
|
||||
" -dirafter [dir] same as -isystem but do it last\n"
|
||||
" -isystem [dir] add additional search path for other .h files\n"
|
||||
" -mllvm [arg] additional arguments to forward to LLVM's option processing\n"
|
||||
"Link Options:\n"
|
||||
" --ar-path $path set the path to ar\n"
|
||||
" --dynamic-linker $path set the path to ld.so\n"
|
||||
" --ar-path [path] set the path to ar\n"
|
||||
" --dynamic-linker [path] set the path to ld.so\n"
|
||||
" --each-lib-rpath add rpath for each used dynamic library\n"
|
||||
" --libc-lib-dir $path directory where libc crt1.o resides\n"
|
||||
" --libc-static-lib-dir $path directory where libc crtbegin.o resides\n"
|
||||
" --msvc-lib-dir $path (windows) directory where vcruntime.lib resides\n"
|
||||
" --kernel32-lib-dir $path (windows) directory where kernel32.lib resides\n"
|
||||
" --library $lib link against lib\n"
|
||||
" --library-path $dir add a directory to the library search path\n"
|
||||
" --linker-script $path use a custom linker script\n"
|
||||
" --object $obj add object file to build\n"
|
||||
" -L$dir alias for --library-path\n"
|
||||
" --libc-lib-dir [path] directory where libc crt1.o resides\n"
|
||||
" --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n"
|
||||
" --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n"
|
||||
" --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n"
|
||||
" --library [lib] link against lib\n"
|
||||
" --library-path [dir] add a directory to the library search path\n"
|
||||
" --linker-script [path] use a custom linker script\n"
|
||||
" --object [obj] add object file to build\n"
|
||||
" -L[dir] alias for --library-path\n"
|
||||
" -rdynamic add all symbols to the dynamic symbol table\n"
|
||||
" -rpath $path add directory to the runtime library search path\n"
|
||||
" -rpath [path] add directory to the runtime library search path\n"
|
||||
" -mconsole (windows) --subsystem console to the linker\n"
|
||||
" -mwindows (windows) --subsystem windows to the linker\n"
|
||||
" -framework $name (darwin) link against framework\n"
|
||||
" -mios-version-min $ver (darwin) set iOS deployment target\n"
|
||||
" -mmacosx-version-min $ver (darwin) set Mac OS X deployment target\n"
|
||||
" --ver-major $ver dynamic library semver major version\n"
|
||||
" --ver-minor $ver dynamic library semver minor version\n"
|
||||
" --ver-patch $ver dynamic library semver patch version\n"
|
||||
" -framework [name] (darwin) link against framework\n"
|
||||
" -mios-version-min [ver] (darwin) set iOS deployment target\n"
|
||||
" -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n"
|
||||
" --ver-major [ver] dynamic library semver major version\n"
|
||||
" --ver-minor [ver] dynamic library semver minor version\n"
|
||||
" --ver-patch [ver] dynamic library semver patch version\n"
|
||||
"Test Options:\n"
|
||||
" --test-filter $text skip tests that do not match filter\n"
|
||||
" --test-name-prefix $text add prefix to all tests\n"
|
||||
" --test-cmd $arg specify test execution command one arg at a time\n"
|
||||
" --test-filter [text] skip tests that do not match filter\n"
|
||||
" --test-name-prefix [text] add prefix to all tests\n"
|
||||
" --test-cmd [arg] specify test execution command one arg at a time\n"
|
||||
" --test-cmd-bin appends test binary path to test cmd args\n"
|
||||
, arg0);
|
||||
return EXIT_FAILURE;
|
||||
|
@ -401,8 +401,8 @@ int main(int argc, char **argv) {
|
|||
"\n"
|
||||
"General Options:\n"
|
||||
" --help Print this help and exit\n"
|
||||
" --build-file $file Override path to build.zig\n"
|
||||
" --cache-dir $path Override path to cache directory\n"
|
||||
" --build-file [file] Override path to build.zig\n"
|
||||
" --cache-dir [path] Override path to cache directory\n"
|
||||
" --verbose Print commands before executing them\n"
|
||||
" --verbose-tokenize Enable compiler debug output for tokenization\n"
|
||||
" --verbose-ast Enable compiler debug output for parsing into an AST\n"
|
||||
|
@ -410,14 +410,14 @@ int main(int argc, char **argv) {
|
|||
" --verbose-ir Enable compiler debug output for Zig IR\n"
|
||||
" --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
|
||||
" --verbose-cimport Enable compiler debug output for C imports\n"
|
||||
" --prefix $path Override default install prefix\n"
|
||||
" --prefix [path] Override default install prefix\n"
|
||||
"\n"
|
||||
"Project-specific options become available when the build file is found.\n"
|
||||
"Run this command with no options to generate a build.zig template.\n"
|
||||
"\n"
|
||||
"Advanced Options:\n"
|
||||
" --build-file $file Override path to build.zig\n"
|
||||
" --cache-dir $path Override path to cache directory\n"
|
||||
" --build-file [file] Override path to build.zig\n"
|
||||
" --cache-dir [path] Override path to cache directory\n"
|
||||
" --verbose-tokenize Enable compiler debug output for tokenization\n"
|
||||
" --verbose-ast Enable compiler debug output for parsing into an AST\n"
|
||||
" --verbose-link Enable compiler debug output for linking\n"
|
||||
|
@ -853,20 +853,22 @@ int main(int argc, char **argv) {
|
|||
|
||||
ZigTarget *non_null_target = target ? target : &native;
|
||||
|
||||
Buf *test_exe_name = buf_sprintf("." OS_SEP "test%s", target_exe_file_ext(non_null_target));
|
||||
Buf *test_exe_name = buf_sprintf("test%s", target_exe_file_ext(non_null_target));
|
||||
Buf *test_exe_path = buf_alloc();
|
||||
os_path_join(full_cache_dir, test_exe_name, test_exe_path);
|
||||
|
||||
for (size_t i = 0; i < test_exec_args.length; i += 1) {
|
||||
if (test_exec_args.items[i] == nullptr) {
|
||||
test_exec_args.items[i] = buf_ptr(test_exe_name);
|
||||
test_exec_args.items[i] = buf_ptr(test_exe_path);
|
||||
}
|
||||
}
|
||||
|
||||
codegen_build(g);
|
||||
codegen_link(g, buf_ptr(test_exe_name));
|
||||
codegen_link(g, buf_ptr(test_exe_path));
|
||||
|
||||
if (!target_can_exec(&native, target)) {
|
||||
fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
|
||||
buf_ptr(test_exe_name));
|
||||
buf_ptr(test_exe_path));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -879,12 +881,12 @@ int main(int argc, char **argv) {
|
|||
os_spawn_process(test_exec_args.items[0], rest_args, &term);
|
||||
} else {
|
||||
ZigList<const char *> no_args = {0};
|
||||
os_spawn_process(buf_ptr(test_exe_name), no_args, &term);
|
||||
os_spawn_process(buf_ptr(test_exe_path), no_args, &term);
|
||||
}
|
||||
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
|
||||
fprintf(stderr, "%s\n", buf_ptr(test_exe_name));
|
||||
fprintf(stderr, "%s\n", buf_ptr(test_exe_path));
|
||||
} else if (timing_info) {
|
||||
codegen_print_timing_report(g, stdout);
|
||||
}
|
||||
|
|
|
@ -1706,7 +1706,7 @@ pub const CommandStep = struct {
|
|||
fn make(step: &Step) -> %void {
|
||||
const self = @fieldParentPtr(CommandStep, "step", step);
|
||||
|
||||
const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else null;
|
||||
const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root;
|
||||
return self.builder.spawnChildEnvMap(cwd, self.env_map, self.argv);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ pub extern "c" fn abort() -> noreturn;
|
|||
pub extern "c" fn exit(code: c_int) -> noreturn;
|
||||
pub extern "c" fn isatty(fd: c_int) -> c_int;
|
||||
pub extern "c" fn close(fd: c_int) -> c_int;
|
||||
pub extern "c" fn fstat(fd: c_int, buf: &stat) -> c_int;
|
||||
pub extern "c" fn fstat(fd: c_int, buf: &Stat) -> c_int;
|
||||
pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) -> isize;
|
||||
pub extern "c" fn open(path: &const u8, oflag: c_int, ...) -> c_int;
|
||||
pub extern "c" fn raise(sig: c_int) -> c_int;
|
||||
|
|
|
@ -17,6 +17,7 @@ error UnsupportedDebugInfo;
|
|||
/// Does not append a newline.
|
||||
/// TODO atomic/multithread support
|
||||
var stderr_file: io.File = undefined;
|
||||
var stderr_file_out_stream: io.FileOutStream = undefined;
|
||||
var stderr_stream: ?&io.OutStream = null;
|
||||
pub fn warn(comptime fmt: []const u8, args: ...) {
|
||||
const stderr = getStderrStream() %% return;
|
||||
|
@ -27,7 +28,8 @@ fn getStderrStream() -> %&io.OutStream {
|
|||
return st;
|
||||
} else {
|
||||
stderr_file = %return io.getStdErr();
|
||||
const st = &stderr_file.out_stream;
|
||||
stderr_file_out_stream = io.FileOutStream.init(&stderr_file);
|
||||
const st = &stderr_file_out_stream.stream;
|
||||
stderr_stream = st;
|
||||
return st;
|
||||
};
|
||||
|
@ -201,7 +203,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_
|
|||
var column: usize = 1;
|
||||
var abs_index: usize = 0;
|
||||
while (true) {
|
||||
const amt_read = %return f.in_stream.read(buf[0..]);
|
||||
const amt_read = %return f.read(buf[0..]);
|
||||
const slice = buf[0..amt_read];
|
||||
|
||||
for (slice) |byte| {
|
||||
|
@ -239,7 +241,9 @@ const ElfStackTrace = struct {
|
|||
}
|
||||
|
||||
pub fn readString(self: &ElfStackTrace) -> %[]u8 {
|
||||
return readStringRaw(self.allocator(), &self.self_exe_file.in_stream);
|
||||
var in_file_stream = io.FileInStream.init(&self.self_exe_file);
|
||||
const in_stream = &in_file_stream.stream;
|
||||
return readStringRaw(self.allocator(), in_stream);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -567,7 +571,9 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
|
|||
}
|
||||
|
||||
fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
|
||||
const in_stream = &st.self_exe_file.in_stream;
|
||||
const in_file = &st.self_exe_file;
|
||||
var in_file_stream = io.FileInStream.init(in_file);
|
||||
const in_stream = &in_file_stream.stream;
|
||||
var result = AbbrevTable.init(st.allocator());
|
||||
while (true) {
|
||||
const abbrev_code = %return readULeb128(in_stream);
|
||||
|
@ -620,7 +626,9 @@ fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) -> ?&
|
|||
|
||||
fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -> %Die {
|
||||
const in_file = &st.self_exe_file;
|
||||
const abbrev_code = %return readULeb128(&in_file.in_stream);
|
||||
var in_file_stream = io.FileInStream.init(in_file);
|
||||
const in_stream = &in_file_stream.stream;
|
||||
const abbrev_code = %return readULeb128(in_stream);
|
||||
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
|
||||
|
||||
var result = Die {
|
||||
|
@ -632,7 +640,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -
|
|||
for (table_entry.attrs.toSliceConst()) |attr, i| {
|
||||
result.attrs.items[i] = Die.Attr {
|
||||
.id = attr.attr_id,
|
||||
.value = %return parseFormValue(st.allocator(), &st.self_exe_file.in_stream, attr.form_id, is_64),
|
||||
.value = %return parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
|
||||
};
|
||||
}
|
||||
return result;
|
||||
|
@ -646,11 +654,14 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||
var this_offset = st.debug_line.offset;
|
||||
var this_index: usize = 0;
|
||||
|
||||
var in_file_stream = io.FileInStream.init(in_file);
|
||||
const in_stream = &in_file_stream.stream;
|
||||
|
||||
while (this_offset < debug_line_end) : (this_index += 1) {
|
||||
%return in_file.seekTo(this_offset);
|
||||
|
||||
var is_64: bool = undefined;
|
||||
const unit_length = %return readInitialLength(&in_file.in_stream, &is_64);
|
||||
const unit_length = %return readInitialLength(in_stream, &is_64);
|
||||
if (unit_length == 0)
|
||||
return error.MissingDebugInfo;
|
||||
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
||||
|
@ -660,28 +671,28 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||
continue;
|
||||
}
|
||||
|
||||
const version = %return in_file.in_stream.readInt(st.elf.is_big_endian, u16);
|
||||
const version = %return in_stream.readInt(st.elf.is_big_endian, u16);
|
||||
if (version != 2) return error.InvalidDebugInfo;
|
||||
|
||||
const prologue_length = %return in_file.in_stream.readInt(st.elf.is_big_endian, u32);
|
||||
const prologue_length = %return in_stream.readInt(st.elf.is_big_endian, u32);
|
||||
const prog_start_offset = (%return in_file.getPos()) + prologue_length;
|
||||
|
||||
const minimum_instruction_length = %return in_file.in_stream.readByte();
|
||||
const minimum_instruction_length = %return in_stream.readByte();
|
||||
if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
|
||||
|
||||
const default_is_stmt = (%return in_file.in_stream.readByte()) != 0;
|
||||
const line_base = %return in_file.in_stream.readByteSigned();
|
||||
const default_is_stmt = (%return in_stream.readByte()) != 0;
|
||||
const line_base = %return in_stream.readByteSigned();
|
||||
|
||||
const line_range = %return in_file.in_stream.readByte();
|
||||
const line_range = %return in_stream.readByte();
|
||||
if (line_range == 0)
|
||||
return error.InvalidDebugInfo;
|
||||
|
||||
const opcode_base = %return in_file.in_stream.readByte();
|
||||
const opcode_base = %return in_stream.readByte();
|
||||
|
||||
const standard_opcode_lengths = %return st.allocator().alloc(u8, opcode_base - 1);
|
||||
|
||||
{var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
|
||||
standard_opcode_lengths[i] = %return in_file.in_stream.readByte();
|
||||
standard_opcode_lengths[i] = %return in_stream.readByte();
|
||||
}}
|
||||
|
||||
var include_directories = ArrayList([]u8).init(st.allocator());
|
||||
|
@ -701,9 +712,9 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||
const file_name = %return st.readString();
|
||||
if (file_name.len == 0)
|
||||
break;
|
||||
const dir_index = %return readULeb128(&in_file.in_stream);
|
||||
const mtime = %return readULeb128(&in_file.in_stream);
|
||||
const len_bytes = %return readULeb128(&in_file.in_stream);
|
||||
const dir_index = %return readULeb128(in_stream);
|
||||
const mtime = %return readULeb128(in_stream);
|
||||
const len_bytes = %return readULeb128(in_stream);
|
||||
%return file_entries.append(FileEntry {
|
||||
.file_name = file_name,
|
||||
.dir_index = dir_index,
|
||||
|
@ -715,14 +726,14 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||
%return in_file.seekTo(prog_start_offset);
|
||||
|
||||
while (true) {
|
||||
const opcode = %return in_file.in_stream.readByte();
|
||||
const opcode = %return in_stream.readByte();
|
||||
|
||||
var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
|
||||
if (opcode == DW.LNS_extended_op) {
|
||||
const op_size = %return readULeb128(&in_file.in_stream);
|
||||
const op_size = %return readULeb128(in_stream);
|
||||
if (op_size < 1)
|
||||
return error.InvalidDebugInfo;
|
||||
sub_op = %return in_file.in_stream.readByte();
|
||||
sub_op = %return in_stream.readByte();
|
||||
switch (sub_op) {
|
||||
DW.LNE_end_sequence => {
|
||||
prog.end_sequence = true;
|
||||
|
@ -730,14 +741,14 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||
return error.MissingDebugInfo;
|
||||
},
|
||||
DW.LNE_set_address => {
|
||||
const addr = %return in_file.in_stream.readInt(st.elf.is_big_endian, usize);
|
||||
const addr = %return in_stream.readInt(st.elf.is_big_endian, usize);
|
||||
prog.address = addr;
|
||||
},
|
||||
DW.LNE_define_file => {
|
||||
const file_name = %return st.readString();
|
||||
const dir_index = %return readULeb128(&in_file.in_stream);
|
||||
const mtime = %return readULeb128(&in_file.in_stream);
|
||||
const len_bytes = %return readULeb128(&in_file.in_stream);
|
||||
const dir_index = %return readULeb128(in_stream);
|
||||
const mtime = %return readULeb128(in_stream);
|
||||
const len_bytes = %return readULeb128(in_stream);
|
||||
%return file_entries.append(FileEntry {
|
||||
.file_name = file_name,
|
||||
.dir_index = dir_index,
|
||||
|
@ -766,19 +777,19 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||
prog.basic_block = false;
|
||||
},
|
||||
DW.LNS_advance_pc => {
|
||||
const arg = %return readULeb128(&in_file.in_stream);
|
||||
const arg = %return readULeb128(in_stream);
|
||||
prog.address += arg * minimum_instruction_length;
|
||||
},
|
||||
DW.LNS_advance_line => {
|
||||
const arg = %return readILeb128(&in_file.in_stream);
|
||||
const arg = %return readILeb128(in_stream);
|
||||
prog.line += arg;
|
||||
},
|
||||
DW.LNS_set_file => {
|
||||
const arg = %return readULeb128(&in_file.in_stream);
|
||||
const arg = %return readULeb128(in_stream);
|
||||
prog.file = arg;
|
||||
},
|
||||
DW.LNS_set_column => {
|
||||
const arg = %return readULeb128(&in_file.in_stream);
|
||||
const arg = %return readULeb128(in_stream);
|
||||
prog.column = arg;
|
||||
},
|
||||
DW.LNS_negate_stmt => {
|
||||
|
@ -792,7 +803,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||
prog.address += inc_addr;
|
||||
},
|
||||
DW.LNS_fixed_advance_pc => {
|
||||
const arg = %return in_file.in_stream.readInt(st.elf.is_big_endian, u16);
|
||||
const arg = %return in_stream.readInt(st.elf.is_big_endian, u16);
|
||||
prog.address += arg;
|
||||
},
|
||||
DW.LNS_set_prologue_end => {
|
||||
|
@ -817,25 +828,29 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
|
|||
const debug_info_end = st.debug_info.offset + st.debug_info.size;
|
||||
var this_unit_offset = st.debug_info.offset;
|
||||
var cu_index: usize = 0;
|
||||
|
||||
var in_file_stream = io.FileInStream.init(&st.self_exe_file);
|
||||
const in_stream = &in_file_stream.stream;
|
||||
|
||||
while (this_unit_offset < debug_info_end) {
|
||||
%return st.self_exe_file.seekTo(this_unit_offset);
|
||||
|
||||
var is_64: bool = undefined;
|
||||
const unit_length = %return readInitialLength(&st.self_exe_file.in_stream, &is_64);
|
||||
const unit_length = %return readInitialLength(in_stream, &is_64);
|
||||
if (unit_length == 0)
|
||||
return;
|
||||
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
||||
|
||||
const version = %return st.self_exe_file.in_stream.readInt(st.elf.is_big_endian, u16);
|
||||
const version = %return in_stream.readInt(st.elf.is_big_endian, u16);
|
||||
if (version < 2 or version > 5) return error.InvalidDebugInfo;
|
||||
|
||||
const debug_abbrev_offset = if (is_64) {
|
||||
%return st.self_exe_file.in_stream.readInt(st.elf.is_big_endian, u64)
|
||||
%return in_stream.readInt(st.elf.is_big_endian, u64)
|
||||
} else {
|
||||
%return st.self_exe_file.in_stream.readInt(st.elf.is_big_endian, u32)
|
||||
%return in_stream.readInt(st.elf.is_big_endian, u32)
|
||||
};
|
||||
|
||||
const address_size = %return st.self_exe_file.in_stream.readByte();
|
||||
const address_size = %return in_stream.readByte();
|
||||
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
||||
|
||||
const compile_unit_pos = %return st.self_exe_file.getPos();
|
||||
|
|
88
std/elf.zig
88
std/elf.zig
|
@ -92,29 +92,32 @@ pub const Elf = struct {
|
|||
elf.in_file = file;
|
||||
elf.auto_close_stream = false;
|
||||
|
||||
var file_stream = io.FileInStream.init(elf.in_file);
|
||||
const in = &file_stream.stream;
|
||||
|
||||
var magic: [4]u8 = undefined;
|
||||
%return elf.in_file.in_stream.readNoEof(magic[0..]);
|
||||
%return in.readNoEof(magic[0..]);
|
||||
if (!mem.eql(u8, magic, "\x7fELF")) return error.InvalidFormat;
|
||||
|
||||
elf.is_64 = switch (%return elf.in_file.in_stream.readByte()) {
|
||||
elf.is_64 = switch (%return in.readByte()) {
|
||||
1 => false,
|
||||
2 => true,
|
||||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
elf.is_big_endian = switch (%return elf.in_file.in_stream.readByte()) {
|
||||
elf.is_big_endian = switch (%return in.readByte()) {
|
||||
1 => false,
|
||||
2 => true,
|
||||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
const version_byte = %return elf.in_file.in_stream.readByte();
|
||||
const version_byte = %return in.readByte();
|
||||
if (version_byte != 1) return error.InvalidFormat;
|
||||
|
||||
// skip over padding
|
||||
%return elf.in_file.seekForward(9);
|
||||
|
||||
elf.file_type = switch (%return elf.in_file.in_stream.readInt(elf.is_big_endian, u16)) {
|
||||
elf.file_type = switch (%return in.readInt(elf.is_big_endian, u16)) {
|
||||
1 => FileType.Relocatable,
|
||||
2 => FileType.Executable,
|
||||
3 => FileType.Shared,
|
||||
|
@ -122,7 +125,7 @@ pub const Elf = struct {
|
|||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
elf.arch = switch (%return elf.in_file.in_stream.readInt(elf.is_big_endian, u16)) {
|
||||
elf.arch = switch (%return in.readInt(elf.is_big_endian, u16)) {
|
||||
0x02 => Arch.Sparc,
|
||||
0x03 => Arch.x86,
|
||||
0x08 => Arch.Mips,
|
||||
|
@ -135,34 +138,34 @@ pub const Elf = struct {
|
|||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
const elf_version = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
|
||||
const elf_version = %return in.readInt(elf.is_big_endian, u32);
|
||||
if (elf_version != 1) return error.InvalidFormat;
|
||||
|
||||
if (elf.is_64) {
|
||||
elf.entry_addr = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
|
||||
elf.program_header_offset = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
|
||||
elf.section_header_offset = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
|
||||
elf.entry_addr = %return in.readInt(elf.is_big_endian, u64);
|
||||
elf.program_header_offset = %return in.readInt(elf.is_big_endian, u64);
|
||||
elf.section_header_offset = %return in.readInt(elf.is_big_endian, u64);
|
||||
} else {
|
||||
elf.entry_addr = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
|
||||
elf.program_header_offset = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
|
||||
elf.section_header_offset = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
|
||||
elf.entry_addr = u64(%return in.readInt(elf.is_big_endian, u32));
|
||||
elf.program_header_offset = u64(%return in.readInt(elf.is_big_endian, u32));
|
||||
elf.section_header_offset = u64(%return in.readInt(elf.is_big_endian, u32));
|
||||
}
|
||||
|
||||
// skip over flags
|
||||
%return elf.in_file.seekForward(4);
|
||||
|
||||
const header_size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
|
||||
const header_size = %return in.readInt(elf.is_big_endian, u16);
|
||||
if ((elf.is_64 and header_size != 64) or
|
||||
(!elf.is_64 and header_size != 52))
|
||||
{
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
const ph_entry_size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
|
||||
const ph_entry_count = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
|
||||
const sh_entry_size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
|
||||
const sh_entry_count = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
|
||||
elf.string_section_index = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u16));
|
||||
const ph_entry_size = %return in.readInt(elf.is_big_endian, u16);
|
||||
const ph_entry_count = %return in.readInt(elf.is_big_endian, u16);
|
||||
const sh_entry_size = %return in.readInt(elf.is_big_endian, u16);
|
||||
const sh_entry_count = %return in.readInt(elf.is_big_endian, u16);
|
||||
elf.string_section_index = u64(%return in.readInt(elf.is_big_endian, u16));
|
||||
|
||||
if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
|
||||
|
||||
|
@ -185,32 +188,32 @@ pub const Elf = struct {
|
|||
if (sh_entry_size != 64) return error.InvalidFormat;
|
||||
|
||||
for (elf.section_headers) |*section| {
|
||||
section.name = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.sh_type = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.flags = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.addr = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.offset = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.link = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.info = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.addr_align = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.ent_size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.name = %return in.readInt(elf.is_big_endian, u32);
|
||||
section.sh_type = %return in.readInt(elf.is_big_endian, u32);
|
||||
section.flags = %return in.readInt(elf.is_big_endian, u64);
|
||||
section.addr = %return in.readInt(elf.is_big_endian, u64);
|
||||
section.offset = %return in.readInt(elf.is_big_endian, u64);
|
||||
section.size = %return in.readInt(elf.is_big_endian, u64);
|
||||
section.link = %return in.readInt(elf.is_big_endian, u32);
|
||||
section.info = %return in.readInt(elf.is_big_endian, u32);
|
||||
section.addr_align = %return in.readInt(elf.is_big_endian, u64);
|
||||
section.ent_size = %return in.readInt(elf.is_big_endian, u64);
|
||||
}
|
||||
} else {
|
||||
if (sh_entry_size != 40) return error.InvalidFormat;
|
||||
|
||||
for (elf.section_headers) |*section| {
|
||||
// TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ?
|
||||
section.name = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.sh_type = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.flags = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.addr = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.offset = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.size = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.link = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.info = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.addr_align = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.ent_size = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.name = %return in.readInt(elf.is_big_endian, u32);
|
||||
section.sh_type = %return in.readInt(elf.is_big_endian, u32);
|
||||
section.flags = u64(%return in.readInt(elf.is_big_endian, u32));
|
||||
section.addr = u64(%return in.readInt(elf.is_big_endian, u32));
|
||||
section.offset = u64(%return in.readInt(elf.is_big_endian, u32));
|
||||
section.size = u64(%return in.readInt(elf.is_big_endian, u32));
|
||||
section.link = %return in.readInt(elf.is_big_endian, u32);
|
||||
section.info = %return in.readInt(elf.is_big_endian, u32);
|
||||
section.addr_align = u64(%return in.readInt(elf.is_big_endian, u32));
|
||||
section.ent_size = u64(%return in.readInt(elf.is_big_endian, u32));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,6 +239,9 @@ pub const Elf = struct {
|
|||
}
|
||||
|
||||
pub fn findSection(elf: &Elf, name: []const u8) -> %?&SectionHeader {
|
||||
var file_stream = io.FileInStream.init(elf.in_file);
|
||||
const in = &file_stream.stream;
|
||||
|
||||
for (elf.section_headers) |*section| {
|
||||
if (section.sh_type == SHT_NULL) continue;
|
||||
|
||||
|
@ -243,12 +249,12 @@ pub const Elf = struct {
|
|||
%return elf.in_file.seekTo(name_offset);
|
||||
|
||||
for (name) |expected_c| {
|
||||
const target_c = %return elf.in_file.in_stream.readByte();
|
||||
const target_c = %return in.readByte();
|
||||
if (target_c == 0 or expected_c != target_c) goto next_section;
|
||||
}
|
||||
|
||||
{
|
||||
const null_byte = %return elf.in_file.in_stream.readByte();
|
||||
const null_byte = %return in.readByte();
|
||||
if (null_byte == 0) return section;
|
||||
}
|
||||
|
||||
|
|
206
std/io.zig
206
std/io.zig
|
@ -76,16 +76,50 @@ pub fn getStdIn() -> %File {
|
|||
return File.openHandle(handle);
|
||||
}
|
||||
|
||||
/// Implementation of InStream trait for File
|
||||
pub const FileInStream = struct {
|
||||
file: &File,
|
||||
stream: InStream,
|
||||
|
||||
pub fn init(file: &File) -> FileInStream {
|
||||
return FileInStream {
|
||||
.file = file,
|
||||
.stream = InStream {
|
||||
.readFn = readFn,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn readFn(in_stream: &InStream, buffer: []u8) -> %usize {
|
||||
const self = @fieldParentPtr(FileInStream, "stream", in_stream);
|
||||
return self.file.read(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
/// Implementation of OutStream trait for File
|
||||
pub const FileOutStream = struct {
|
||||
file: &File,
|
||||
stream: OutStream,
|
||||
|
||||
pub fn init(file: &File) -> FileOutStream {
|
||||
return FileOutStream {
|
||||
.file = file,
|
||||
.stream = OutStream {
|
||||
.writeFn = writeFn,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn writeFn(out_stream: &OutStream, bytes: []const u8) -> %void {
|
||||
const self = @fieldParentPtr(FileOutStream, "stream", out_stream);
|
||||
return self.file.write(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
pub const File = struct {
|
||||
/// The OS-specific file descriptor or file handle.
|
||||
handle: os.FileHandle,
|
||||
|
||||
/// A file has the `InStream` trait
|
||||
in_stream: InStream,
|
||||
|
||||
/// A file has the `OutStream` trait
|
||||
out_stream: OutStream,
|
||||
|
||||
/// `path` may need to be copied in memory to add a null terminating byte. In this case
|
||||
/// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
|
||||
/// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
|
||||
|
@ -135,12 +169,6 @@ pub const File = struct {
|
|||
pub fn openHandle(handle: os.FileHandle) -> File {
|
||||
return File {
|
||||
.handle = handle,
|
||||
.out_stream = OutStream {
|
||||
.writeFn = writeFn,
|
||||
},
|
||||
.in_stream = InStream {
|
||||
.readFn = readFn,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -232,8 +260,7 @@ pub const File = struct {
|
|||
return usize(stat.size);
|
||||
}
|
||||
|
||||
fn readFn(in_stream: &InStream, buffer: []u8) -> %usize {
|
||||
const self = @fieldParentPtr(File, "in_stream", in_stream);
|
||||
pub fn read(self: &File, buffer: []u8) -> %usize {
|
||||
if (is_posix) {
|
||||
var index: usize = 0;
|
||||
while (index < buffer.len) {
|
||||
|
@ -275,8 +302,7 @@ pub const File = struct {
|
|||
}
|
||||
}
|
||||
|
||||
fn writeFn(out_stream: &OutStream, bytes: []const u8) -> %void {
|
||||
const self = @fieldParentPtr(File, "out_stream", out_stream);
|
||||
fn write(self: &File, bytes: []const u8) -> %void {
|
||||
if (is_posix) {
|
||||
%return os.posixWrite(self.handle, bytes);
|
||||
} else if (is_windows) {
|
||||
|
@ -285,19 +311,8 @@ pub const File = struct {
|
|||
@compileError("Unsupported OS");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// `path` may need to be copied in memory to add a null terminating byte. In this case
|
||||
/// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed
|
||||
/// size buffer is too small, and the provided allocator is null, `error.NameTooLong` is returned.
|
||||
/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
|
||||
pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) -> %void {
|
||||
var file = %return File.openWrite(path, allocator);
|
||||
defer file.close();
|
||||
%return file.out_stream.write(data);
|
||||
}
|
||||
|
||||
error StreamTooLong;
|
||||
error EndOfStream;
|
||||
|
||||
|
@ -446,3 +461,140 @@ pub const OutStream = struct {
|
|||
return self.writeFn(self, slice);
|
||||
}
|
||||
};
|
||||
|
||||
/// `path` may need to be copied in memory to add a null terminating byte. In this case
|
||||
/// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed
|
||||
/// size buffer is too small, and the provided allocator is null, `error.NameTooLong` is returned.
|
||||
/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
|
||||
pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) -> %void {
|
||||
var file = %return File.openWrite(path, allocator);
|
||||
defer file.close();
|
||||
%return file.write(data);
|
||||
}
|
||||
|
||||
pub const BufferedInStream = BufferedInStreamCustom(os.page_size);
|
||||
|
||||
pub fn BufferedInStreamCustom(comptime buffer_size: usize) -> type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
|
||||
pub stream: InStream,
|
||||
|
||||
unbuffered_in_stream: &InStream,
|
||||
|
||||
buffer: [buffer_size]u8,
|
||||
start_index: usize,
|
||||
end_index: usize,
|
||||
|
||||
pub fn init(unbuffered_in_stream: &InStream) -> Self {
|
||||
return Self {
|
||||
.unbuffered_in_stream = unbuffered_in_stream,
|
||||
.buffer = undefined,
|
||||
|
||||
// Initialize these two fields to buffer_size so that
|
||||
// in `readFn` we treat the state as being able to read
|
||||
// more from the unbuffered stream. If we set them to 0
|
||||
// and 0, the code would think we already hit EOF.
|
||||
.start_index = buffer_size,
|
||||
.end_index = buffer_size,
|
||||
|
||||
.stream = InStream {
|
||||
.readFn = readFn,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn readFn(in_stream: &InStream, dest: []u8) -> %usize {
|
||||
const self = @fieldParentPtr(Self, "stream", in_stream);
|
||||
|
||||
var dest_index: usize = 0;
|
||||
while (true) {
|
||||
const dest_space = dest.len - dest_index;
|
||||
if (dest_space == 0) {
|
||||
return dest_index;
|
||||
}
|
||||
const amt_buffered = self.end_index - self.start_index;
|
||||
if (amt_buffered == 0) {
|
||||
assert(self.end_index <= buffer_size);
|
||||
if (self.end_index == buffer_size) {
|
||||
// we can read more data from the unbuffered stream
|
||||
if (dest_space < buffer_size) {
|
||||
self.start_index = 0;
|
||||
self.end_index = %return self.unbuffered_in_stream.read(self.buffer[0..]);
|
||||
} else {
|
||||
// asking for so much data that buffering is actually less efficient.
|
||||
// forward the request directly to the unbuffered stream
|
||||
const amt_read = %return self.unbuffered_in_stream.read(dest[dest_index..]);
|
||||
return dest_index + amt_read;
|
||||
}
|
||||
} else {
|
||||
// reading from the unbuffered stream returned less than we asked for
|
||||
// so we cannot read any more data.
|
||||
return dest_index;
|
||||
}
|
||||
}
|
||||
const copy_amount = math.min(dest_space, amt_buffered);
|
||||
const copy_end_index = self.start_index + copy_amount;
|
||||
mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]);
|
||||
self.start_index = copy_end_index;
|
||||
dest_index += copy_amount;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub const BufferedOutStream = BufferedOutStreamCustom(os.page_size);
|
||||
|
||||
pub fn BufferedOutStreamCustom(comptime buffer_size: usize) -> type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
|
||||
pub stream: OutStream,
|
||||
|
||||
unbuffered_out_stream: &OutStream,
|
||||
|
||||
buffer: [buffer_size]u8,
|
||||
index: usize,
|
||||
|
||||
pub fn init(unbuffered_out_stream: &OutStream) -> Self {
|
||||
return Self {
|
||||
.unbuffered_out_stream = unbuffered_out_stream,
|
||||
.buffer = undefined,
|
||||
.index = 0,
|
||||
.stream = OutStream {
|
||||
.writeFn = writeFn,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn flush(self: &Self) -> %void {
|
||||
if (self.index == 0)
|
||||
return;
|
||||
|
||||
%return self.unbuffered_out_stream.write(self.buffer[0..self.index]);
|
||||
self.index = 0;
|
||||
}
|
||||
|
||||
fn writeFn(out_stream: &OutStream, bytes: []const u8) -> %void {
|
||||
const self = @fieldParentPtr(Self, "stream", out_stream);
|
||||
|
||||
if (bytes.len >= self.buffer.len) {
|
||||
%return self.flush();
|
||||
return self.unbuffered_out_stream.write(bytes);
|
||||
}
|
||||
var src_index: usize = 0;
|
||||
|
||||
while (src_index < bytes.len) {
|
||||
const dest_space_left = self.buffer.len - self.index;
|
||||
const copy_amt = math.min(dest_space_left, bytes.len - src_index);
|
||||
mem.copy(u8, self.buffer[self.index..], bytes[src_index..src_index + copy_amt]);
|
||||
self.index += copy_amt;
|
||||
assert(self.index <= self.buffer.len);
|
||||
if (self.index == self.buffer.len) {
|
||||
%return self.flush();
|
||||
}
|
||||
src_index += copy_amt;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -128,12 +128,12 @@ pub fn isatty(fd: i32) -> bool {
|
|||
c.isatty(fd) != 0
|
||||
}
|
||||
|
||||
pub fn fstat(fd: i32, buf: &c.stat) -> usize {
|
||||
pub fn fstat(fd: i32, buf: &c.Stat) -> usize {
|
||||
errnoWrap(c.fstat(fd, buf))
|
||||
}
|
||||
|
||||
pub fn lseek(fd: i32, offset: isize, whence: c_int) -> usize {
|
||||
errnoWrap(c.lseek(fd, buf, whence))
|
||||
errnoWrap(c.lseek(fd, offset, whence))
|
||||
}
|
||||
|
||||
pub fn open(path: &const u8, flags: u32, mode: usize) -> usize {
|
||||
|
@ -268,6 +268,7 @@ pub const sigset_t = c.sigset_t;
|
|||
pub const empty_sigset = sigset_t(0);
|
||||
|
||||
pub const timespec = c.timespec;
|
||||
pub const Stat = c.Stat;
|
||||
|
||||
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
|
||||
pub const Sigaction = struct {
|
||||
|
|
|
@ -730,8 +730,8 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [
|
|||
|
||||
var buf: [page_size]u8 = undefined;
|
||||
while (true) {
|
||||
const amt = %return in_file.in_stream.read(buf[0..]);
|
||||
%return out_file.out_stream.write(buf[0..amt]);
|
||||
const amt = %return in_file.read(buf[0..]);
|
||||
%return out_file.write(buf[0..amt]);
|
||||
if (amt != buf.len)
|
||||
return rename(allocator, tmp_path, dest_path);
|
||||
}
|
||||
|
|
|
@ -44,9 +44,22 @@ pub fn main() -> %void {
|
|||
var prefix: ?[]const u8 = null;
|
||||
|
||||
var stderr_file = io.getStdErr();
|
||||
var stderr_stream: %&io.OutStream = if (stderr_file) |*f| &f.out_stream else |err| err;
|
||||
var stderr_file_stream: io.FileOutStream = undefined;
|
||||
var stderr_stream: %&io.OutStream = if (stderr_file) |*f| {
|
||||
stderr_file_stream = io.FileOutStream.init(f);
|
||||
&stderr_file_stream.stream
|
||||
} else |err| {
|
||||
err
|
||||
};
|
||||
|
||||
var stdout_file = io.getStdOut();
|
||||
var stdout_stream: %&io.OutStream = if (stdout_file) |*f| &f.out_stream else |err| err;
|
||||
var stdout_file_stream: io.FileOutStream = undefined;
|
||||
var stdout_stream: %&io.OutStream = if (stdout_file) |*f| {
|
||||
stdout_file_stream = io.FileOutStream.init(f);
|
||||
&stdout_file_stream.stream
|
||||
} else |err| {
|
||||
err
|
||||
};
|
||||
|
||||
while (arg_it.next(allocator)) |err_or_arg| {
|
||||
const arg = %return unwrapArg(err_or_arg);
|
||||
|
@ -135,7 +148,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
|
|||
\\General Options:
|
||||
\\ --help Print this help and exit
|
||||
\\ --verbose Print commands before executing them
|
||||
\\ --prefix $path Override default install prefix
|
||||
\\ --prefix [path] Override default install prefix
|
||||
\\
|
||||
\\Project-Specific Options:
|
||||
\\
|
||||
|
@ -146,7 +159,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
|
|||
} else {
|
||||
for (builder.available_options_list.toSliceConst()) |option| {
|
||||
const name = %return fmt.allocPrint(allocator,
|
||||
" -D{}=${}", option.name, Builder.typeIdName(option.type_id));
|
||||
" -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));
|
||||
defer allocator.free(name);
|
||||
%return out_stream.print("{s24} {}\n", name, option.description);
|
||||
}
|
||||
|
@ -155,8 +168,8 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
|
|||
%return out_stream.write(
|
||||
\\
|
||||
\\Advanced Options:
|
||||
\\ --build-file $file Override path to build.zig
|
||||
\\ --cache-dir $path Override path to zig cache directory
|
||||
\\ --build-file [file] Override path to build.zig
|
||||
\\ --cache-dir [path] Override path to zig cache directory
|
||||
\\ --verbose-tokenize Enable compiler debug output for tokenization
|
||||
\\ --verbose-ast Enable compiler debug output for parsing into an AST
|
||||
\\ --verbose-link Enable compiler debug output for linking
|
||||
|
|
|
@ -136,3 +136,57 @@ const AlignTestEnum = enum {
|
|||
A: [9]u8,
|
||||
B: u64,
|
||||
};
|
||||
|
||||
const ValueCount0 = enum {};
|
||||
const ValueCount1 = enum { I0 };
|
||||
const ValueCount2 = enum { I0, I1 };
|
||||
const ValueCount256 = enum {
|
||||
I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,
|
||||
I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,
|
||||
I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,
|
||||
I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,
|
||||
I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,
|
||||
I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,
|
||||
I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,
|
||||
I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,
|
||||
I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,
|
||||
I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,
|
||||
I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,
|
||||
I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,
|
||||
I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,
|
||||
I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,
|
||||
I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,
|
||||
I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,
|
||||
I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,
|
||||
I250, I251, I252, I253, I254, I255
|
||||
};
|
||||
const ValueCount257 = enum {
|
||||
I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,
|
||||
I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,
|
||||
I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,
|
||||
I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,
|
||||
I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,
|
||||
I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,
|
||||
I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,
|
||||
I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,
|
||||
I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,
|
||||
I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,
|
||||
I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,
|
||||
I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,
|
||||
I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,
|
||||
I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,
|
||||
I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,
|
||||
I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,
|
||||
I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,
|
||||
I250, I251, I252, I253, I254, I255, I256
|
||||
};
|
||||
|
||||
test "enum sizes" {
|
||||
comptime {
|
||||
assert(@sizeOf(ValueCount0) == 0);
|
||||
assert(@sizeOf(ValueCount1) == 0);
|
||||
assert(@sizeOf(ValueCount2) == 1);
|
||||
assert(@sizeOf(ValueCount256) == 1);
|
||||
assert(@sizeOf(ValueCount257) == 2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\
|
||||
\\pub fn main() -> %void {
|
||||
\\ privateFunction();
|
||||
\\ const stdout = &(%%getStdOut()).out_stream;
|
||||
\\ const stdout = &(FileOutStream.init(&%%getStdOut()).stream);
|
||||
\\ %%stdout.print("OK 2\n");
|
||||
\\}
|
||||
\\
|
||||
|
@ -32,7 +32,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\// purposefully conflicting function with main.zig
|
||||
\\// but it's private so it should be OK
|
||||
\\fn privateFunction() {
|
||||
\\ const stdout = &(%%getStdOut()).out_stream;
|
||||
\\ const stdout = &(FileOutStream.init(&%%getStdOut()).stream);
|
||||
\\ %%stdout.print("OK 1\n");
|
||||
\\}
|
||||
\\
|
||||
|
@ -58,7 +58,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
tc.addSourceFile("foo.zig",
|
||||
\\use @import("std").io;
|
||||
\\pub fn foo_function() {
|
||||
\\ const stdout = &(%%getStdOut()).out_stream;
|
||||
\\ const stdout = &(FileOutStream.init(&%%getStdOut()).stream);
|
||||
\\ %%stdout.print("OK\n");
|
||||
\\}
|
||||
);
|
||||
|
@ -69,7 +69,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\
|
||||
\\pub fn bar_function() {
|
||||
\\ if (foo_function()) {
|
||||
\\ const stdout = &(%%getStdOut()).out_stream;
|
||||
\\ const stdout = &(FileOutStream.init(&%%getStdOut()).stream);
|
||||
\\ %%stdout.print("OK\n");
|
||||
\\ }
|
||||
\\}
|
||||
|
@ -101,7 +101,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\pub const a_text = "OK\n";
|
||||
\\
|
||||
\\pub fn ok() {
|
||||
\\ const stdout = &(%%io.getStdOut()).out_stream;
|
||||
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
|
||||
\\ %%stdout.print(b_text);
|
||||
\\}
|
||||
);
|
||||
|
@ -119,7 +119,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\const io = @import("std").io;
|
||||
\\
|
||||
\\pub fn main() -> %void {
|
||||
\\ const stdout = &(%%io.getStdOut()).out_stream;
|
||||
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
|
||||
\\ %%stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a'));
|
||||
\\}
|
||||
, "Hello, world!\n0012 012 a\n");
|
||||
|
@ -272,7 +272,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\ var x_local : i32 = print_ok(x);
|
||||
\\}
|
||||
\\fn print_ok(val: @typeOf(x)) -> @typeOf(foo) {
|
||||
\\ const stdout = &(%%io.getStdOut()).out_stream;
|
||||
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
|
||||
\\ %%stdout.print("OK\n");
|
||||
\\ return 0;
|
||||
\\}
|
||||
|
@ -354,7 +354,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\pub fn main() -> %void {
|
||||
\\ const bar = Bar {.field2 = 13,};
|
||||
\\ const foo = Foo {.field1 = bar,};
|
||||
\\ const stdout = &(%%io.getStdOut()).out_stream;
|
||||
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
|
||||
\\ if (!foo.method()) {
|
||||
\\ %%stdout.print("BAD\n");
|
||||
\\ }
|
||||
|
@ -368,7 +368,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
cases.add("defer with only fallthrough",
|
||||
\\const io = @import("std").io;
|
||||
\\pub fn main() -> %void {
|
||||
\\ const stdout = &(%%io.getStdOut()).out_stream;
|
||||
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
|
||||
\\ %%stdout.print("before\n");
|
||||
\\ defer %%stdout.print("defer1\n");
|
||||
\\ defer %%stdout.print("defer2\n");
|
||||
|
@ -381,7 +381,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\const io = @import("std").io;
|
||||
\\const os = @import("std").os;
|
||||
\\pub fn main() -> %void {
|
||||
\\ const stdout = &(%%io.getStdOut()).out_stream;
|
||||
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
|
||||
\\ %%stdout.print("before\n");
|
||||
\\ defer %%stdout.print("defer1\n");
|
||||
\\ defer %%stdout.print("defer2\n");
|
||||
|
@ -398,7 +398,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\ do_test() %% return;
|
||||
\\}
|
||||
\\fn do_test() -> %void {
|
||||
\\ const stdout = &(%%io.getStdOut()).out_stream;
|
||||
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
|
||||
\\ %%stdout.print("before\n");
|
||||
\\ defer %%stdout.print("defer1\n");
|
||||
\\ %defer %%stdout.print("deferErr\n");
|
||||
|
@ -418,7 +418,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\ do_test() %% return;
|
||||
\\}
|
||||
\\fn do_test() -> %void {
|
||||
\\ const stdout = &(%%io.getStdOut()).out_stream;
|
||||
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
|
||||
\\ %%stdout.print("before\n");
|
||||
\\ defer %%stdout.print("defer1\n");
|
||||
\\ %defer %%stdout.print("deferErr\n");
|
||||
|
@ -435,7 +435,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
|||
\\const io = @import("std").io;
|
||||
\\
|
||||
\\pub fn main() -> %void {
|
||||
\\ const stdout = &(%%io.getStdOut()).out_stream;
|
||||
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
|
||||
\\ %%stdout.print(foo_txt);
|
||||
\\}
|
||||
, "1234\nabcd\n");
|
||||
|
|
|
@ -2335,4 +2335,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
|||
\\const Foo = enum {};
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
|
||||
|
||||
cases.add("calling var args extern function, passing array instead of pointer",
|
||||
\\export fn entry() {
|
||||
\\ foo("hello");
|
||||
\\}
|
||||
\\pub extern fn foo(format: &const u8, ...);
|
||||
,
|
||||
".tmp_source.zig:2:9: error: expected type '&const u8', found '[5]u8'");
|
||||
}
|
||||
|
|
|
@ -249,8 +249,11 @@ pub const CompareOutputContext = struct {
|
|||
var stdout = Buffer.initNull(b.allocator);
|
||||
var stderr = Buffer.initNull(b.allocator);
|
||||
|
||||
%%(??child.stdout).in_stream.readAllBuffer(&stdout, max_stdout_size);
|
||||
%%(??child.stderr).in_stream.readAllBuffer(&stderr, max_stdout_size);
|
||||
var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
|
||||
var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
|
||||
|
||||
%%stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size);
|
||||
%%stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size);
|
||||
|
||||
const term = child.wait() %% |err| {
|
||||
debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
|
||||
|
@ -576,8 +579,11 @@ pub const CompileErrorContext = struct {
|
|||
var stdout_buf = Buffer.initNull(b.allocator);
|
||||
var stderr_buf = Buffer.initNull(b.allocator);
|
||||
|
||||
%%(??child.stdout).in_stream.readAllBuffer(&stdout_buf, max_stdout_size);
|
||||
%%(??child.stderr).in_stream.readAllBuffer(&stderr_buf, max_stdout_size);
|
||||
var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
|
||||
var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
|
||||
|
||||
%%stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size);
|
||||
%%stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size);
|
||||
|
||||
const term = child.wait() %% |err| {
|
||||
debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err));
|
||||
|
@ -718,7 +724,8 @@ pub const BuildExamplesContext = struct {
|
|||
}
|
||||
|
||||
var zig_args = ArrayList([]const u8).init(b.allocator);
|
||||
%%zig_args.append(b.zig_exe);
|
||||
const rel_zig_exe = %%os.path.relative(b.allocator, b.build_root, b.zig_exe);
|
||||
%%zig_args.append(rel_zig_exe);
|
||||
%%zig_args.append("build");
|
||||
|
||||
%%zig_args.append("--build-file");
|
||||
|
@ -844,8 +851,11 @@ pub const ParseCContext = struct {
|
|||
var stdout_buf = Buffer.initNull(b.allocator);
|
||||
var stderr_buf = Buffer.initNull(b.allocator);
|
||||
|
||||
%%(??child.stdout).in_stream.readAllBuffer(&stdout_buf, max_stdout_size);
|
||||
%%(??child.stderr).in_stream.readAllBuffer(&stderr_buf, max_stdout_size);
|
||||
var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
|
||||
var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
|
||||
|
||||
%%stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size);
|
||||
%%stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size);
|
||||
|
||||
const term = child.wait() %% |err| {
|
||||
debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err));
|
||||
|
|
Loading…
Reference in New Issue