explicitly return from blocks
instead of last statement being expression value closes #629
This commit is contained in:
parent
8bc523219c
commit
d917815d81
@ -49,7 +49,7 @@ fn gen(in: &io.InStream, out: &io.OutStream) {
|
|||||||
if (err == error.EndOfStream) {
|
if (err == error.EndOfStream) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std.debug.panic("{}", err)
|
std.debug.panic("{}", err);
|
||||||
};
|
};
|
||||||
switch (state) {
|
switch (state) {
|
||||||
State.Start => switch (byte) {
|
State.Start => switch (byte) {
|
||||||
|
@ -3021,14 +3021,13 @@ const assert = @import("std").debug.assert;</code></pre>
|
|||||||
<pre><code class="zig">const assert = @import("std").debug.assert;
|
<pre><code class="zig">const assert = @import("std").debug.assert;
|
||||||
|
|
||||||
// Functions are declared like this
|
// Functions are declared like this
|
||||||
// The last expression in the function can be used as the return value.
|
|
||||||
fn add(a: i8, b: i8) -> i8 {
|
fn add(a: i8, b: i8) -> i8 {
|
||||||
if (a == 0) {
|
if (a == 0) {
|
||||||
// You can still return manually if needed.
|
// You can still return manually if needed.
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
a + b
|
return a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The export specifier makes a function externally visible in the generated
|
// The export specifier makes a function externally visible in the generated
|
||||||
@ -5847,7 +5846,7 @@ ParamDeclList = "(" list(ParamDecl, ",") ")"
|
|||||||
|
|
||||||
ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
|
ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
|
||||||
|
|
||||||
Block = option(Symbol ":") "{" many(Statement) option(Expression) "}"
|
Block = option(Symbol ":") "{" many(Statement) "}"
|
||||||
|
|
||||||
Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
|
Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export fn add(a: i32, b: i32) -> i32 {
|
export fn add(a: i32, b: i32) -> i32 {
|
||||||
a + b
|
return a + b;
|
||||||
}
|
}
|
||||||
|
@ -111,11 +111,11 @@ pub const Parser = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(self: &Parser) -> %&ast.NodeRoot {
|
pub fn parse(self: &Parser) -> %&ast.NodeRoot {
|
||||||
const result = self.parseInner() %% |err| {
|
const result = self.parseInner() %% |err| x: {
|
||||||
if (self.cleanup_root_node) |root_node| {
|
if (self.cleanup_root_node) |root_node| {
|
||||||
self.freeAst(root_node);
|
self.freeAst(root_node);
|
||||||
}
|
}
|
||||||
err
|
break :x err;
|
||||||
};
|
};
|
||||||
self.cleanup_root_node = null;
|
self.cleanup_root_node = null;
|
||||||
return result;
|
return result;
|
||||||
@ -125,12 +125,12 @@ pub const Parser = struct {
|
|||||||
var stack = self.initUtilityArrayList(State);
|
var stack = self.initUtilityArrayList(State);
|
||||||
defer self.deinitUtilityArrayList(stack);
|
defer self.deinitUtilityArrayList(stack);
|
||||||
|
|
||||||
const root_node = {
|
const root_node = x: {
|
||||||
const root_node = %return self.createRoot();
|
const root_node = %return self.createRoot();
|
||||||
%defer self.allocator.destroy(root_node);
|
%defer self.allocator.destroy(root_node);
|
||||||
// This stack append has to succeed for freeAst to work
|
// This stack append has to succeed for freeAst to work
|
||||||
%return stack.append(State.TopLevel);
|
%return stack.append(State.TopLevel);
|
||||||
root_node
|
break :x root_node;
|
||||||
};
|
};
|
||||||
assert(self.cleanup_root_node == null);
|
assert(self.cleanup_root_node == null);
|
||||||
self.cleanup_root_node = root_node;
|
self.cleanup_root_node = root_node;
|
||||||
@ -462,7 +462,7 @@ pub const Parser = struct {
|
|||||||
} else if (token.id == Token.Id.Keyword_noalias) {
|
} else if (token.id == Token.Id.Keyword_noalias) {
|
||||||
param_decl.noalias_token = token;
|
param_decl.noalias_token = token;
|
||||||
token = self.getNextToken();
|
token = self.getNextToken();
|
||||||
};
|
}
|
||||||
if (token.id == Token.Id.Identifier) {
|
if (token.id == Token.Id.Identifier) {
|
||||||
const next_token = self.getNextToken();
|
const next_token = self.getNextToken();
|
||||||
if (next_token.id == Token.Id.Colon) {
|
if (next_token.id == Token.Id.Colon) {
|
||||||
@ -793,14 +793,14 @@ pub const Parser = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getNextToken(self: &Parser) -> Token {
|
fn getNextToken(self: &Parser) -> Token {
|
||||||
return if (self.put_back_count != 0) {
|
if (self.put_back_count != 0) {
|
||||||
const put_back_index = self.put_back_count - 1;
|
const put_back_index = self.put_back_count - 1;
|
||||||
const put_back_token = self.put_back_tokens[put_back_index];
|
const put_back_token = self.put_back_tokens[put_back_index];
|
||||||
self.put_back_count = put_back_index;
|
self.put_back_count = put_back_index;
|
||||||
put_back_token
|
return put_back_token;
|
||||||
} else {
|
} else {
|
||||||
self.tokenizer.next()
|
return self.tokenizer.next();
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const RenderAstFrame = struct {
|
const RenderAstFrame = struct {
|
||||||
@ -873,7 +873,7 @@ pub const Parser = struct {
|
|||||||
Token.Id.Keyword_pub => %return stream.print("pub "),
|
Token.Id.Keyword_pub => %return stream.print("pub "),
|
||||||
Token.Id.Keyword_export => %return stream.print("export "),
|
Token.Id.Keyword_export => %return stream.print("export "),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
if (fn_proto.extern_token) |extern_token| {
|
if (fn_proto.extern_token) |extern_token| {
|
||||||
%return stream.print("{} ", self.tokenizer.getTokenSlice(extern_token));
|
%return stream.print("{} ", self.tokenizer.getTokenSlice(extern_token));
|
||||||
@ -1102,7 +1102,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) -> %[]u8 {
|
|||||||
// TODO test for memory leaks
|
// TODO test for memory leaks
|
||||||
// TODO test for valid frees
|
// TODO test for valid frees
|
||||||
fn testCanonical(source: []const u8) {
|
fn testCanonical(source: []const u8) {
|
||||||
const needed_alloc_count = {
|
const needed_alloc_count = x: {
|
||||||
// Try it once with unlimited memory, make sure it works
|
// Try it once with unlimited memory, make sure it works
|
||||||
var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
|
var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
|
||||||
var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));
|
var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));
|
||||||
@ -1116,7 +1116,7 @@ fn testCanonical(source: []const u8) {
|
|||||||
@panic("test failed");
|
@panic("test failed");
|
||||||
}
|
}
|
||||||
failing_allocator.allocator.free(result_source);
|
failing_allocator.allocator.free(result_source);
|
||||||
failing_allocator.index
|
break :x failing_allocator.index;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO make this pass
|
// TODO make this pass
|
||||||
|
@ -26,7 +26,6 @@ struct ScopeFnDef;
|
|||||||
struct TypeTableEntry;
|
struct TypeTableEntry;
|
||||||
struct VariableTableEntry;
|
struct VariableTableEntry;
|
||||||
struct ErrorTableEntry;
|
struct ErrorTableEntry;
|
||||||
struct LabelTableEntry;
|
|
||||||
struct BuiltinFnEntry;
|
struct BuiltinFnEntry;
|
||||||
struct TypeStructField;
|
struct TypeStructField;
|
||||||
struct CodeGen;
|
struct CodeGen;
|
||||||
@ -54,7 +53,6 @@ struct IrExecutable {
|
|||||||
size_t *backward_branch_count;
|
size_t *backward_branch_count;
|
||||||
size_t backward_branch_quota;
|
size_t backward_branch_quota;
|
||||||
bool invalid;
|
bool invalid;
|
||||||
ZigList<LabelTableEntry *> all_labels;
|
|
||||||
ZigList<IrGotoItem> goto_list;
|
ZigList<IrGotoItem> goto_list;
|
||||||
bool is_inline;
|
bool is_inline;
|
||||||
FnTableEntry *fn_entry;
|
FnTableEntry *fn_entry;
|
||||||
@ -452,7 +450,6 @@ struct AstNodeParamDecl {
|
|||||||
struct AstNodeBlock {
|
struct AstNodeBlock {
|
||||||
Buf *name;
|
Buf *name;
|
||||||
ZigList<AstNode *> statements;
|
ZigList<AstNode *> statements;
|
||||||
bool last_statement_is_result_expression;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ReturnKind {
|
enum ReturnKind {
|
||||||
@ -1644,12 +1641,6 @@ struct ErrorTableEntry {
|
|||||||
ConstExprValue *cached_error_name_val;
|
ConstExprValue *cached_error_name_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LabelTableEntry {
|
|
||||||
AstNode *decl_node;
|
|
||||||
IrBasicBlock *bb;
|
|
||||||
bool used;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ScopeId {
|
enum ScopeId {
|
||||||
ScopeIdDecls,
|
ScopeIdDecls,
|
||||||
ScopeIdBlock,
|
ScopeIdBlock,
|
||||||
@ -1693,7 +1684,12 @@ struct ScopeDecls {
|
|||||||
struct ScopeBlock {
|
struct ScopeBlock {
|
||||||
Scope base;
|
Scope base;
|
||||||
|
|
||||||
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
|
Buf *name;
|
||||||
|
IrBasicBlock *end_block;
|
||||||
|
IrInstruction *is_comptime;
|
||||||
|
ZigList<IrInstruction *> *incoming_values;
|
||||||
|
ZigList<IrBasicBlock *> *incoming_blocks;
|
||||||
|
|
||||||
bool safety_off;
|
bool safety_off;
|
||||||
AstNode *safety_set_node;
|
AstNode *safety_set_node;
|
||||||
bool fast_math_off;
|
bool fast_math_off;
|
||||||
|
@ -110,7 +110,7 @@ ScopeBlock *create_block_scope(AstNode *node, Scope *parent) {
|
|||||||
assert(node->type == NodeTypeBlock);
|
assert(node->type == NodeTypeBlock);
|
||||||
ScopeBlock *scope = allocate<ScopeBlock>(1);
|
ScopeBlock *scope = allocate<ScopeBlock>(1);
|
||||||
init_scope(&scope->base, ScopeIdBlock, node, parent);
|
init_scope(&scope->base, ScopeIdBlock, node, parent);
|
||||||
scope->label_table.init(1);
|
scope->name = node->data.block.name;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,10 +478,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
|||||||
AstNode *statement = node->data.block.statements.at(i);
|
AstNode *statement = node->data.block.statements.at(i);
|
||||||
print_indent(ar);
|
print_indent(ar);
|
||||||
render_node_grouped(ar, statement);
|
render_node_grouped(ar, statement);
|
||||||
if (!(i == node->data.block.statements.length - 1 &&
|
fprintf(ar->f, ";");
|
||||||
node->data.block.last_statement_is_result_expression)) {
|
|
||||||
fprintf(ar->f, ";");
|
|
||||||
}
|
|
||||||
fprintf(ar->f, "\n");
|
fprintf(ar->f, "\n");
|
||||||
}
|
}
|
||||||
ar->indent -= ar->indent_size;
|
ar->indent -= ar->indent_size;
|
||||||
|
98
src/ir.cpp
98
src/ir.cpp
@ -3514,7 +3514,11 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s
|
|||||||
static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
|
static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
|
||||||
assert(block_node->type == NodeTypeBlock);
|
assert(block_node->type == NodeTypeBlock);
|
||||||
|
|
||||||
|
ZigList<IrInstruction *> incoming_values = {0};
|
||||||
|
ZigList<IrBasicBlock *> incoming_blocks = {0};
|
||||||
|
|
||||||
ScopeBlock *scope_block = create_block_scope(block_node, parent_scope);
|
ScopeBlock *scope_block = create_block_scope(block_node, parent_scope);
|
||||||
|
|
||||||
Scope *outer_block_scope = &scope_block->base;
|
Scope *outer_block_scope = &scope_block->base;
|
||||||
Scope *child_scope = outer_block_scope;
|
Scope *child_scope = outer_block_scope;
|
||||||
|
|
||||||
@ -3528,9 +3532,15 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
|
|||||||
return ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
|
return ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (block_node->data.block.name != nullptr) {
|
||||||
|
scope_block->incoming_blocks = &incoming_blocks;
|
||||||
|
scope_block->incoming_values = &incoming_values;
|
||||||
|
scope_block->end_block = ir_build_basic_block(irb, parent_scope, "BlockEnd");
|
||||||
|
scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope));
|
||||||
|
}
|
||||||
|
|
||||||
bool is_continuation_unreachable = false;
|
bool is_continuation_unreachable = false;
|
||||||
IrInstruction *noreturn_return_value = nullptr;
|
IrInstruction *noreturn_return_value = nullptr;
|
||||||
IrInstruction *return_value = nullptr;
|
|
||||||
for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
|
for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
|
||||||
AstNode *statement_node = block_node->data.block.statements.at(i);
|
AstNode *statement_node = block_node->data.block.statements.at(i);
|
||||||
|
|
||||||
@ -3548,39 +3558,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
|
|||||||
// variable declarations start a new scope
|
// variable declarations start a new scope
|
||||||
IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value;
|
IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value;
|
||||||
child_scope = decl_var_instruction->var->child_scope;
|
child_scope = decl_var_instruction->var->child_scope;
|
||||||
} else {
|
} else if (statement_value != irb->codegen->invalid_instruction) {
|
||||||
// label, defer, variable declaration will never be the result expression
|
// this statement's value must be void
|
||||||
if (block_node->data.block.last_statement_is_result_expression &&
|
ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value));
|
||||||
i == block_node->data.block.statements.length - 1) {
|
|
||||||
// this is the result value statement
|
|
||||||
return_value = statement_value;
|
|
||||||
} else {
|
|
||||||
// there are more statements ahead of this one. this statement's value must be void
|
|
||||||
if (statement_value != irb->codegen->invalid_instruction) {
|
|
||||||
ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_continuation_unreachable) {
|
if (is_continuation_unreachable) {
|
||||||
assert(noreturn_return_value != nullptr);
|
assert(noreturn_return_value != nullptr);
|
||||||
return noreturn_return_value;
|
if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) {
|
||||||
}
|
return noreturn_return_value;
|
||||||
// control flow falls out of block
|
}
|
||||||
|
|
||||||
if (block_node->data.block.last_statement_is_result_expression) {
|
|
||||||
// return value was determined by the last statement
|
|
||||||
assert(return_value != nullptr);
|
|
||||||
} else {
|
} else {
|
||||||
// return value is implicitly void
|
incoming_blocks.append(irb->current_basic_block);
|
||||||
assert(return_value == nullptr);
|
incoming_values.append(ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)));
|
||||||
return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
|
if (block_node->data.block.name != nullptr) {
|
||||||
|
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
|
||||||
return return_value;
|
ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
|
||||||
|
ir_set_cursor_at_end(irb, scope_block->end_block);
|
||||||
|
return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
|
||||||
|
} else {
|
||||||
|
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
|
||||||
|
return ir_mark_gen(ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
|
static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
|
||||||
@ -5952,6 +5954,31 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo
|
|||||||
return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval);
|
return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) {
|
||||||
|
IrInstruction *is_comptime;
|
||||||
|
if (ir_should_inline(irb->exec, break_scope)) {
|
||||||
|
is_comptime = ir_build_const_bool(irb, break_scope, node, true);
|
||||||
|
} else {
|
||||||
|
is_comptime = block_scope->is_comptime;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrInstruction *result_value;
|
||||||
|
if (node->data.break_expr.expr) {
|
||||||
|
result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope);
|
||||||
|
if (result_value == irb->codegen->invalid_instruction)
|
||||||
|
return irb->codegen->invalid_instruction;
|
||||||
|
} else {
|
||||||
|
result_value = ir_build_const_void(irb, break_scope, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
IrBasicBlock *dest_block = block_scope->end_block;
|
||||||
|
ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false);
|
||||||
|
|
||||||
|
block_scope->incoming_blocks->append(irb->current_basic_block);
|
||||||
|
block_scope->incoming_values->append(result_value);
|
||||||
|
return ir_build_br(irb, break_scope, node, dest_block, is_comptime);
|
||||||
|
}
|
||||||
|
|
||||||
static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) {
|
static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) {
|
||||||
assert(node->type == NodeTypeBreak);
|
assert(node->type == NodeTypeBreak);
|
||||||
|
|
||||||
@ -5959,14 +5986,14 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
|
|||||||
// * function definition scope or global scope => error, break outside loop
|
// * function definition scope or global scope => error, break outside loop
|
||||||
// * defer expression scope => error, cannot break out of defer expression
|
// * defer expression scope => error, cannot break out of defer expression
|
||||||
// * loop scope => OK
|
// * loop scope => OK
|
||||||
|
// * (if it's a labeled break) labeled block => OK
|
||||||
|
|
||||||
Scope *search_scope = break_scope;
|
Scope *search_scope = break_scope;
|
||||||
ScopeLoop *loop_scope;
|
ScopeLoop *loop_scope;
|
||||||
bool saw_any_loop_scope = false;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
|
if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
|
||||||
if (saw_any_loop_scope) {
|
if (node->data.break_expr.name != nullptr) {
|
||||||
add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.break_expr.name)));
|
add_node_error(irb->codegen, node, buf_sprintf("label not found: '%s'", buf_ptr(node->data.break_expr.name)));
|
||||||
return irb->codegen->invalid_instruction;
|
return irb->codegen->invalid_instruction;
|
||||||
} else {
|
} else {
|
||||||
add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop"));
|
add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop"));
|
||||||
@ -5977,13 +6004,20 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
|
|||||||
return irb->codegen->invalid_instruction;
|
return irb->codegen->invalid_instruction;
|
||||||
} else if (search_scope->id == ScopeIdLoop) {
|
} else if (search_scope->id == ScopeIdLoop) {
|
||||||
ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
|
ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
|
||||||
saw_any_loop_scope = true;
|
|
||||||
if (node->data.break_expr.name == nullptr ||
|
if (node->data.break_expr.name == nullptr ||
|
||||||
(this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name)))
|
(this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name)))
|
||||||
{
|
{
|
||||||
loop_scope = this_loop_scope;
|
loop_scope = this_loop_scope;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (search_scope->id == ScopeIdBlock) {
|
||||||
|
ScopeBlock *this_block_scope = (ScopeBlock *)search_scope;
|
||||||
|
if (node->data.break_expr.name != nullptr &&
|
||||||
|
(this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name)))
|
||||||
|
{
|
||||||
|
assert(this_block_scope->end_block != nullptr);
|
||||||
|
return ir_gen_return_from_block(irb, break_scope, node, this_block_scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
search_scope = search_scope->parent;
|
search_scope = search_scope->parent;
|
||||||
}
|
}
|
||||||
@ -6022,10 +6056,9 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
|
|||||||
|
|
||||||
Scope *search_scope = continue_scope;
|
Scope *search_scope = continue_scope;
|
||||||
ScopeLoop *loop_scope;
|
ScopeLoop *loop_scope;
|
||||||
bool saw_any_loop_scope = false;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
|
if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
|
||||||
if (saw_any_loop_scope) {
|
if (node->data.continue_expr.name != nullptr) {
|
||||||
add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name)));
|
add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name)));
|
||||||
return irb->codegen->invalid_instruction;
|
return irb->codegen->invalid_instruction;
|
||||||
} else {
|
} else {
|
||||||
@ -6037,7 +6070,6 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
|
|||||||
return irb->codegen->invalid_instruction;
|
return irb->codegen->invalid_instruction;
|
||||||
} else if (search_scope->id == ScopeIdLoop) {
|
} else if (search_scope->id == ScopeIdLoop) {
|
||||||
ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
|
ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
|
||||||
saw_any_loop_scope = true;
|
|
||||||
if (node->data.continue_expr.name == nullptr ||
|
if (node->data.continue_expr.name == nullptr ||
|
||||||
(this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name)))
|
(this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name)))
|
||||||
{
|
{
|
||||||
|
@ -748,7 +748,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
|
|||||||
node->data.fn_call_expr.is_builtin = true;
|
node->data.fn_call_expr.is_builtin = true;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
} else if (token->id == TokenIdSymbol) {
|
}
|
||||||
|
|
||||||
|
AstNode *block_expr_node = ast_parse_block_expr(pc, token_index, false);
|
||||||
|
if (block_expr_node) {
|
||||||
|
return block_expr_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token->id == TokenIdSymbol) {
|
||||||
*token_index += 1;
|
*token_index += 1;
|
||||||
AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
|
AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
|
||||||
node->data.symbol_expr.symbol = token_buf(token);
|
node->data.symbol_expr.symbol = token_buf(token);
|
||||||
@ -760,11 +767,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
|
|||||||
return grouped_expr_node;
|
return grouped_expr_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *block_expr_node = ast_parse_block_expr(pc, token_index, false);
|
|
||||||
if (block_expr_node) {
|
|
||||||
return block_expr_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
AstNode *array_type_node = ast_parse_array_type_expr(pc, token_index, false);
|
AstNode *array_type_node = ast_parse_array_type_expr(pc, token_index, false);
|
||||||
if (array_type_node) {
|
if (array_type_node) {
|
||||||
return array_type_node;
|
return array_type_node;
|
||||||
@ -2145,9 +2147,6 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Label: token(Symbol) token(Colon)
|
|
||||||
*/
|
|
||||||
static bool statement_terminates_without_semicolon(AstNode *node) {
|
static bool statement_terminates_without_semicolon(AstNode *node) {
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case NodeTypeIfBoolExpr:
|
case NodeTypeIfBoolExpr:
|
||||||
@ -2179,7 +2178,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Block = option(Symbol ":") "{" many(Statement) option(Expression) "}"
|
Block = option(Symbol ":") "{" many(Statement) "}"
|
||||||
Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ExportDecl
|
Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ExportDecl
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) {
|
static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||||
@ -2220,6 +2219,12 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
last_token = &pc->tokens->at(*token_index);
|
||||||
|
if (last_token->id == TokenIdRBrace) {
|
||||||
|
*token_index += 1;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
AstNode *statement_node = ast_parse_local_var_decl(pc, token_index);
|
AstNode *statement_node = ast_parse_local_var_decl(pc, token_index);
|
||||||
if (!statement_node)
|
if (!statement_node)
|
||||||
statement_node = ast_parse_defer_expr(pc, token_index);
|
statement_node = ast_parse_defer_expr(pc, token_index);
|
||||||
@ -2228,32 +2233,14 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
|
|||||||
if (!statement_node)
|
if (!statement_node)
|
||||||
statement_node = ast_parse_expression(pc, token_index, false);
|
statement_node = ast_parse_expression(pc, token_index, false);
|
||||||
|
|
||||||
bool semicolon_expected = true;
|
if (!statement_node) {
|
||||||
if (statement_node) {
|
ast_invalid_token_error(pc, last_token);
|
||||||
node->data.block.statements.append(statement_node);
|
|
||||||
if (statement_terminates_without_semicolon(statement_node)) {
|
|
||||||
semicolon_expected = false;
|
|
||||||
} else {
|
|
||||||
if (statement_node->type == NodeTypeDefer) {
|
|
||||||
// defer without a block body requires a semicolon
|
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
|
||||||
ast_expect_token(pc, token, TokenIdSemicolon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node->data.block.last_statement_is_result_expression = statement_node && statement_node->type != NodeTypeDefer;
|
node->data.block.statements.append(statement_node);
|
||||||
|
|
||||||
last_token = &pc->tokens->at(*token_index);
|
if (!statement_terminates_without_semicolon(statement_node)) {
|
||||||
if (last_token->id == TokenIdRBrace) {
|
ast_eat_token(pc, token_index, TokenIdSemicolon);
|
||||||
*token_index += 1;
|
|
||||||
return node;
|
|
||||||
} else if (!semicolon_expected) {
|
|
||||||
continue;
|
|
||||||
} else if (last_token->id == TokenIdSemicolon) {
|
|
||||||
*token_index += 1;
|
|
||||||
} else {
|
|
||||||
ast_invalid_token_error(pc, last_token);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
|
@ -171,6 +171,20 @@ static AstNode * trans_create_node(Context *c, NodeType id) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AstNode *trans_create_node_break(Context *c, Buf *label_name, AstNode *value_node) {
|
||||||
|
AstNode *node = trans_create_node(c, NodeTypeBreak);
|
||||||
|
node->data.break_expr.name = label_name;
|
||||||
|
node->data.break_expr.expr = value_node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AstNode *trans_create_node_return(Context *c, AstNode *value_node) {
|
||||||
|
AstNode *node = trans_create_node(c, NodeTypeReturnExpr);
|
||||||
|
node->data.return_expr.kind = ReturnKindUnconditional;
|
||||||
|
node->data.return_expr.expr = value_node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
static AstNode *trans_create_node_if(Context *c, AstNode *cond_node, AstNode *then_node, AstNode *else_node) {
|
static AstNode *trans_create_node_if(Context *c, AstNode *cond_node, AstNode *then_node, AstNode *else_node) {
|
||||||
AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr);
|
AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr);
|
||||||
node->data.if_bool_expr.condition = cond_node;
|
node->data.if_bool_expr.condition = cond_node;
|
||||||
@ -372,8 +386,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r
|
|||||||
|
|
||||||
AstNode *block = trans_create_node(c, NodeTypeBlock);
|
AstNode *block = trans_create_node(c, NodeTypeBlock);
|
||||||
block->data.block.statements.resize(1);
|
block->data.block.statements.resize(1);
|
||||||
block->data.block.statements.items[0] = fn_call_node;
|
block->data.block.statements.items[0] = trans_create_node_return(c, fn_call_node);
|
||||||
block->data.block.last_statement_is_result_expression = true;
|
|
||||||
|
|
||||||
fn_def->data.fn_def.body = block;
|
fn_def->data.fn_def.body = block;
|
||||||
return fn_def;
|
return fn_def;
|
||||||
@ -1140,13 +1153,15 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco
|
|||||||
} else {
|
} else {
|
||||||
// worst case
|
// worst case
|
||||||
// c: lhs = rhs
|
// c: lhs = rhs
|
||||||
// zig: {
|
// zig: x: {
|
||||||
// zig: const _tmp = rhs;
|
// zig: const _tmp = rhs;
|
||||||
// zig: lhs = _tmp;
|
// zig: lhs = _tmp;
|
||||||
// zig: _tmp
|
// zig: break :x _tmp
|
||||||
// zig: }
|
// zig: }
|
||||||
|
|
||||||
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
||||||
|
Buf *label_name = buf_create_from_str("x");
|
||||||
|
child_scope->node->data.block.name = label_name;
|
||||||
|
|
||||||
// const _tmp = rhs;
|
// const _tmp = rhs;
|
||||||
AstNode *rhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, rhs, TransRValue);
|
AstNode *rhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, rhs, TransRValue);
|
||||||
@ -1163,9 +1178,9 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco
|
|||||||
trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign,
|
trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign,
|
||||||
trans_create_node_symbol(c, tmp_var_name)));
|
trans_create_node_symbol(c, tmp_var_name)));
|
||||||
|
|
||||||
// _tmp
|
// break :x _tmp
|
||||||
child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
|
AstNode *tmp_symbol_node = trans_create_node_symbol(c, tmp_var_name);
|
||||||
child_scope->node->data.block.last_statement_is_result_expression = true;
|
child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, tmp_symbol_node));
|
||||||
|
|
||||||
return child_scope->node;
|
return child_scope->node;
|
||||||
}
|
}
|
||||||
@ -1270,6 +1285,9 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
|
|||||||
case BO_Comma:
|
case BO_Comma:
|
||||||
{
|
{
|
||||||
TransScopeBlock *scope_block = trans_scope_block_create(c, scope);
|
TransScopeBlock *scope_block = trans_scope_block_create(c, scope);
|
||||||
|
Buf *label_name = buf_create_from_str("x");
|
||||||
|
scope_block->node->data.block.name = label_name;
|
||||||
|
|
||||||
AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue);
|
AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue);
|
||||||
if (lhs == nullptr)
|
if (lhs == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -1278,9 +1296,7 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
|
|||||||
AstNode *rhs = trans_expr(c, result_used, &scope_block->base, stmt->getRHS(), TransRValue);
|
AstNode *rhs = trans_expr(c, result_used, &scope_block->base, stmt->getRHS(), TransRValue);
|
||||||
if (rhs == nullptr)
|
if (rhs == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
scope_block->node->data.block.statements.append(maybe_suppress_result(c, result_used, rhs));
|
scope_block->node->data.block.statements.append(trans_create_node_break(c, label_name, maybe_suppress_result(c, result_used, rhs)));
|
||||||
|
|
||||||
scope_block->node->data.block.last_statement_is_result_expression = true;
|
|
||||||
return scope_block->node;
|
return scope_block->node;
|
||||||
}
|
}
|
||||||
case BO_MulAssign:
|
case BO_MulAssign:
|
||||||
@ -1320,14 +1336,16 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
|
|||||||
} else {
|
} else {
|
||||||
// need more complexity. worst case, this looks like this:
|
// need more complexity. worst case, this looks like this:
|
||||||
// c: lhs >>= rhs
|
// c: lhs >>= rhs
|
||||||
// zig: {
|
// zig: x: {
|
||||||
// zig: const _ref = &lhs;
|
// zig: const _ref = &lhs;
|
||||||
// zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs));
|
// zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs));
|
||||||
// zig: *_ref
|
// zig: break :x *_ref
|
||||||
// zig: }
|
// zig: }
|
||||||
// where u5 is the appropriate type
|
// where u5 is the appropriate type
|
||||||
|
|
||||||
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
||||||
|
Buf *label_name = buf_create_from_str("x");
|
||||||
|
child_scope->node->data.block.name = label_name;
|
||||||
|
|
||||||
// const _ref = &lhs;
|
// const _ref = &lhs;
|
||||||
AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
|
AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
|
||||||
@ -1369,11 +1387,11 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
|
|||||||
child_scope->node->data.block.statements.append(assign_statement);
|
child_scope->node->data.block.statements.append(assign_statement);
|
||||||
|
|
||||||
if (result_used == ResultUsedYes) {
|
if (result_used == ResultUsedYes) {
|
||||||
// *_ref
|
// break :x *_ref
|
||||||
child_scope->node->data.block.statements.append(
|
child_scope->node->data.block.statements.append(
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_break(c, label_name,
|
||||||
trans_create_node_symbol(c, tmp_var_name)));
|
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||||
child_scope->node->data.block.last_statement_is_result_expression = true;
|
trans_create_node_symbol(c, tmp_var_name))));
|
||||||
}
|
}
|
||||||
|
|
||||||
return child_scope->node;
|
return child_scope->node;
|
||||||
@ -1394,13 +1412,15 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
|
|||||||
} else {
|
} else {
|
||||||
// need more complexity. worst case, this looks like this:
|
// need more complexity. worst case, this looks like this:
|
||||||
// c: lhs += rhs
|
// c: lhs += rhs
|
||||||
// zig: {
|
// zig: x: {
|
||||||
// zig: const _ref = &lhs;
|
// zig: const _ref = &lhs;
|
||||||
// zig: *_ref = *_ref + rhs;
|
// zig: *_ref = *_ref + rhs;
|
||||||
// zig: *_ref
|
// zig: break :x *_ref
|
||||||
// zig: }
|
// zig: }
|
||||||
|
|
||||||
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
||||||
|
Buf *label_name = buf_create_from_str("x");
|
||||||
|
child_scope->node->data.block.name = label_name;
|
||||||
|
|
||||||
// const _ref = &lhs;
|
// const _ref = &lhs;
|
||||||
AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
|
AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
|
||||||
@ -1427,11 +1447,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
|
|||||||
rhs));
|
rhs));
|
||||||
child_scope->node->data.block.statements.append(assign_statement);
|
child_scope->node->data.block.statements.append(assign_statement);
|
||||||
|
|
||||||
// *_ref
|
// break :x *_ref
|
||||||
child_scope->node->data.block.statements.append(
|
child_scope->node->data.block.statements.append(
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_break(c, label_name,
|
||||||
trans_create_node_symbol(c, tmp_var_name)));
|
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||||
child_scope->node->data.block.last_statement_is_result_expression = true;
|
trans_create_node_symbol(c, tmp_var_name))));
|
||||||
|
|
||||||
return child_scope->node;
|
return child_scope->node;
|
||||||
}
|
}
|
||||||
@ -1726,13 +1746,15 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
|
|||||||
}
|
}
|
||||||
// worst case
|
// worst case
|
||||||
// c: expr++
|
// c: expr++
|
||||||
// zig: {
|
// zig: x: {
|
||||||
// zig: const _ref = &expr;
|
// zig: const _ref = &expr;
|
||||||
// zig: const _tmp = *_ref;
|
// zig: const _tmp = *_ref;
|
||||||
// zig: *_ref += 1;
|
// zig: *_ref += 1;
|
||||||
// zig: _tmp
|
// zig: break :x _tmp
|
||||||
// zig: }
|
// zig: }
|
||||||
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
||||||
|
Buf *label_name = buf_create_from_str("x");
|
||||||
|
child_scope->node->data.block.name = label_name;
|
||||||
|
|
||||||
// const _ref = &expr;
|
// const _ref = &expr;
|
||||||
AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
|
AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
|
||||||
@ -1758,9 +1780,8 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
|
|||||||
trans_create_node_unsigned(c, 1));
|
trans_create_node_unsigned(c, 1));
|
||||||
child_scope->node->data.block.statements.append(assign_statement);
|
child_scope->node->data.block.statements.append(assign_statement);
|
||||||
|
|
||||||
// _tmp
|
// break :x _tmp
|
||||||
child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
|
child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, trans_create_node_symbol(c, tmp_var_name)));
|
||||||
child_scope->node->data.block.last_statement_is_result_expression = true;
|
|
||||||
|
|
||||||
return child_scope->node;
|
return child_scope->node;
|
||||||
}
|
}
|
||||||
@ -1781,12 +1802,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
|
|||||||
}
|
}
|
||||||
// worst case
|
// worst case
|
||||||
// c: ++expr
|
// c: ++expr
|
||||||
// zig: {
|
// zig: x: {
|
||||||
// zig: const _ref = &expr;
|
// zig: const _ref = &expr;
|
||||||
// zig: *_ref += 1;
|
// zig: *_ref += 1;
|
||||||
// zig: *_ref
|
// zig: break :x *_ref
|
||||||
// zig: }
|
// zig: }
|
||||||
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
||||||
|
Buf *label_name = buf_create_from_str("x");
|
||||||
|
child_scope->node->data.block.name = label_name;
|
||||||
|
|
||||||
// const _ref = &expr;
|
// const _ref = &expr;
|
||||||
AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
|
AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
|
||||||
@ -1805,11 +1828,10 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
|
|||||||
trans_create_node_unsigned(c, 1));
|
trans_create_node_unsigned(c, 1));
|
||||||
child_scope->node->data.block.statements.append(assign_statement);
|
child_scope->node->data.block.statements.append(assign_statement);
|
||||||
|
|
||||||
// *_ref
|
// break :x *_ref
|
||||||
AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
|
AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||||
trans_create_node_symbol(c, ref_var_name));
|
trans_create_node_symbol(c, ref_var_name));
|
||||||
child_scope->node->data.block.statements.append(deref_expr);
|
child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));
|
||||||
child_scope->node->data.block.last_statement_is_result_expression = true;
|
|
||||||
|
|
||||||
return child_scope->node;
|
return child_scope->node;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ pub fn ArrayList(comptime T: type) -> type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
|
pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
|
||||||
struct {
|
return struct {
|
||||||
const Self = this;
|
const Self = this;
|
||||||
|
|
||||||
/// Use toSlice instead of slicing this directly, because if you don't
|
/// Use toSlice instead of slicing this directly, because if you don't
|
||||||
@ -20,11 +20,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
|
|||||||
|
|
||||||
/// Deinitialize with `deinit` or use `toOwnedSlice`.
|
/// Deinitialize with `deinit` or use `toOwnedSlice`.
|
||||||
pub fn init(allocator: &Allocator) -> Self {
|
pub fn init(allocator: &Allocator) -> Self {
|
||||||
Self {
|
return Self {
|
||||||
.items = []align(A) T{},
|
.items = []align(A) T{},
|
||||||
.len = 0,
|
.len = 0,
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(l: &Self) {
|
pub fn deinit(l: &Self) {
|
||||||
@ -107,7 +107,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
|
|||||||
return null;
|
return null;
|
||||||
return self.pop();
|
return self.pop();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "basic ArrayList test" {
|
test "basic ArrayList test" {
|
||||||
|
@ -30,9 +30,9 @@ pub const Buffer = struct {
|
|||||||
/// * ::replaceContentsBuffer
|
/// * ::replaceContentsBuffer
|
||||||
/// * ::resize
|
/// * ::resize
|
||||||
pub fn initNull(allocator: &Allocator) -> Buffer {
|
pub fn initNull(allocator: &Allocator) -> Buffer {
|
||||||
Buffer {
|
return Buffer {
|
||||||
.list = ArrayList(u8).init(allocator),
|
.list = ArrayList(u8).init(allocator),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Must deinitialize with deinit.
|
/// Must deinitialize with deinit.
|
||||||
@ -120,7 +120,7 @@ pub const Buffer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn eql(self: &const Buffer, m: []const u8) -> bool {
|
pub fn eql(self: &const Buffer, m: []const u8) -> bool {
|
||||||
mem.eql(u8, self.toSliceConst(), m)
|
return mem.eql(u8, self.toSliceConst(), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn startsWith(self: &const Buffer, m: []const u8) -> bool {
|
pub fn startsWith(self: &const Buffer, m: []const u8) -> bool {
|
||||||
|
@ -221,11 +221,11 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version {
|
pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version {
|
||||||
Version {
|
return Version {
|
||||||
.major = major,
|
.major = major,
|
||||||
.minor = minor,
|
.minor = minor,
|
||||||
.patch = patch,
|
.patch = patch,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addCIncludePath(self: &Builder, path: []const u8) {
|
pub fn addCIncludePath(self: &Builder, path: []const u8) {
|
||||||
@ -432,16 +432,16 @@ pub const Builder = struct {
|
|||||||
const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false;
|
const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false;
|
||||||
const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false;
|
const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false;
|
||||||
|
|
||||||
const mode = if (release_safe and !release_fast) {
|
const mode = if (release_safe and !release_fast)
|
||||||
builtin.Mode.ReleaseSafe
|
builtin.Mode.ReleaseSafe
|
||||||
} else if (release_fast and !release_safe) {
|
else if (release_fast and !release_safe)
|
||||||
builtin.Mode.ReleaseFast
|
builtin.Mode.ReleaseFast
|
||||||
} else if (!release_fast and !release_safe) {
|
else if (!release_fast and !release_safe)
|
||||||
builtin.Mode.Debug
|
builtin.Mode.Debug
|
||||||
} else {
|
else x: {
|
||||||
warn("Both -Drelease-safe and -Drelease-fast specified");
|
warn("Both -Drelease-safe and -Drelease-fast specified");
|
||||||
self.markInvalidUserInput();
|
self.markInvalidUserInput();
|
||||||
builtin.Mode.Debug
|
break :x builtin.Mode.Debug;
|
||||||
};
|
};
|
||||||
self.release_mode = mode;
|
self.release_mode = mode;
|
||||||
return mode;
|
return mode;
|
||||||
@ -506,7 +506,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn typeToEnum(comptime T: type) -> TypeId {
|
fn typeToEnum(comptime T: type) -> TypeId {
|
||||||
switch (@typeId(T)) {
|
return switch (@typeId(T)) {
|
||||||
builtin.TypeId.Int => TypeId.Int,
|
builtin.TypeId.Int => TypeId.Int,
|
||||||
builtin.TypeId.Float => TypeId.Float,
|
builtin.TypeId.Float => TypeId.Float,
|
||||||
builtin.TypeId.Bool => TypeId.Bool,
|
builtin.TypeId.Bool => TypeId.Bool,
|
||||||
@ -515,7 +515,7 @@ pub const Builder = struct {
|
|||||||
[]const []const u8 => TypeId.List,
|
[]const []const u8 => TypeId.List,
|
||||||
else => @compileError("Unsupported type: " ++ @typeName(T)),
|
else => @compileError("Unsupported type: " ++ @typeName(T)),
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn markInvalidUserInput(self: &Builder) {
|
fn markInvalidUserInput(self: &Builder) {
|
||||||
@ -590,8 +590,7 @@ pub const Builder = struct {
|
|||||||
|
|
||||||
return error.UncleanExit;
|
return error.UncleanExit;
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn makePath(self: &Builder, path: []const u8) -> %void {
|
pub fn makePath(self: &Builder, path: []const u8) -> %void {
|
||||||
@ -662,13 +661,12 @@ pub const Builder = struct {
|
|||||||
if (builtin.environ == builtin.Environ.msvc) {
|
if (builtin.environ == builtin.Environ.msvc) {
|
||||||
return "cl.exe";
|
return "cl.exe";
|
||||||
} else {
|
} else {
|
||||||
return os.getEnvVarOwned(self.allocator, "CC") %% |err| {
|
return os.getEnvVarOwned(self.allocator, "CC") %% |err|
|
||||||
if (err == error.EnvironmentVariableNotFound) {
|
if (err == error.EnvironmentVariableNotFound)
|
||||||
([]const u8)("cc")
|
([]const u8)("cc")
|
||||||
} else {
|
else
|
||||||
debug.panic("Unable to get environment variable: {}", err);
|
debug.panic("Unable to get environment variable: {}", err)
|
||||||
}
|
;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1079,11 +1077,10 @@ pub const LibExeObjStep = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOutputPath(self: &LibExeObjStep) -> []const u8 {
|
pub fn getOutputPath(self: &LibExeObjStep) -> []const u8 {
|
||||||
if (self.output_path) |output_path| {
|
return if (self.output_path) |output_path|
|
||||||
output_path
|
output_path
|
||||||
} else {
|
else
|
||||||
%%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename)
|
%%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setOutputHPath(self: &LibExeObjStep, file_path: []const u8) {
|
pub fn setOutputHPath(self: &LibExeObjStep, file_path: []const u8) {
|
||||||
@ -1096,11 +1093,10 @@ pub const LibExeObjStep = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOutputHPath(self: &LibExeObjStep) -> []const u8 {
|
pub fn getOutputHPath(self: &LibExeObjStep) -> []const u8 {
|
||||||
if (self.output_h_path) |output_h_path| {
|
return if (self.output_h_path) |output_h_path|
|
||||||
output_h_path
|
output_h_path
|
||||||
} else {
|
else
|
||||||
%%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename)
|
%%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) {
|
pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) {
|
||||||
@ -1618,7 +1614,7 @@ pub const TestStep = struct {
|
|||||||
|
|
||||||
pub fn init(builder: &Builder, root_src: []const u8) -> TestStep {
|
pub fn init(builder: &Builder, root_src: []const u8) -> TestStep {
|
||||||
const step_name = builder.fmt("test {}", root_src);
|
const step_name = builder.fmt("test {}", root_src);
|
||||||
TestStep {
|
return TestStep {
|
||||||
.step = Step.init(step_name, builder.allocator, make),
|
.step = Step.init(step_name, builder.allocator, make),
|
||||||
.builder = builder,
|
.builder = builder,
|
||||||
.root_src = root_src,
|
.root_src = root_src,
|
||||||
@ -1629,7 +1625,7 @@ pub const TestStep = struct {
|
|||||||
.link_libs = BufSet.init(builder.allocator),
|
.link_libs = BufSet.init(builder.allocator),
|
||||||
.target = Target { .Native = {} },
|
.target = Target { .Native = {} },
|
||||||
.exec_cmd_args = null,
|
.exec_cmd_args = null,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setVerbose(self: &TestStep, value: bool) {
|
pub fn setVerbose(self: &TestStep, value: bool) {
|
||||||
@ -1936,16 +1932,16 @@ pub const Step = struct {
|
|||||||
done_flag: bool,
|
done_flag: bool,
|
||||||
|
|
||||||
pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)->%void) -> Step {
|
pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)->%void) -> Step {
|
||||||
Step {
|
return Step {
|
||||||
.name = name,
|
.name = name,
|
||||||
.makeFn = makeFn,
|
.makeFn = makeFn,
|
||||||
.dependencies = ArrayList(&Step).init(allocator),
|
.dependencies = ArrayList(&Step).init(allocator),
|
||||||
.loop_flag = false,
|
.loop_flag = false,
|
||||||
.done_flag = false,
|
.done_flag = false,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
pub fn initNoOp(name: []const u8, allocator: &Allocator) -> Step {
|
pub fn initNoOp(name: []const u8, allocator: &Allocator) -> Step {
|
||||||
init(name, allocator, makeNoOp)
|
return init(name, allocator, makeNoOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make(self: &Step) -> %void {
|
pub fn make(self: &Step) -> %void {
|
||||||
|
@ -17,7 +17,7 @@ pub fn cmp(a: &const u8, b: &const u8) -> i8 {
|
|||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toSliceConst(str: &const u8) -> []const u8 {
|
pub fn toSliceConst(str: &const u8) -> []const u8 {
|
||||||
|
@ -32,7 +32,7 @@ fn getStderrStream() -> %&io.OutStream {
|
|||||||
const st = &stderr_file_out_stream.stream;
|
const st = &stderr_file_out_stream.stream;
|
||||||
stderr_stream = st;
|
stderr_stream = st;
|
||||||
return st;
|
return st;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
|
/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
|
||||||
@ -52,9 +52,9 @@ pub fn assert(ok: bool) {
|
|||||||
// we insert an explicit call to @panic instead of unreachable.
|
// we insert an explicit call to @panic instead of unreachable.
|
||||||
// TODO we should use `assertOrPanic` in tests and remove this logic.
|
// TODO we should use `assertOrPanic` in tests and remove this logic.
|
||||||
if (builtin.is_test) {
|
if (builtin.is_test) {
|
||||||
@panic("assertion failure")
|
@panic("assertion failure");
|
||||||
} else {
|
} else {
|
||||||
unreachable // assertion failure
|
unreachable; // assertion failure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +175,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
|
|||||||
return_address, compile_unit_name);
|
return_address, compile_unit_name);
|
||||||
},
|
},
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
builtin.ObjectFormat.coff => {
|
builtin.ObjectFormat.coff => {
|
||||||
@ -357,7 +357,7 @@ const Die = struct {
|
|||||||
FormValue.String => |value| value,
|
FormValue.String => |value| value,
|
||||||
FormValue.StrPtr => |offset| getString(st, offset),
|
FormValue.StrPtr => |offset| getString(st, offset),
|
||||||
else => error.InvalidDebugInfo,
|
else => error.InvalidDebugInfo,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -403,7 +403,7 @@ const LineNumberProgram = struct {
|
|||||||
pub fn init(is_stmt: bool, include_dirs: []const []const u8,
|
pub fn init(is_stmt: bool, include_dirs: []const []const u8,
|
||||||
file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
|
file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
|
||||||
{
|
{
|
||||||
LineNumberProgram {
|
return LineNumberProgram {
|
||||||
.address = 0,
|
.address = 0,
|
||||||
.file = 1,
|
.file = 1,
|
||||||
.line = 1,
|
.line = 1,
|
||||||
@ -421,7 +421,7 @@ const LineNumberProgram = struct {
|
|||||||
.prev_is_stmt = undefined,
|
.prev_is_stmt = undefined,
|
||||||
.prev_basic_block = undefined,
|
.prev_basic_block = undefined,
|
||||||
.prev_end_sequence = undefined,
|
.prev_end_sequence = undefined,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
|
pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
|
||||||
@ -430,14 +430,11 @@ const LineNumberProgram = struct {
|
|||||||
return error.MissingDebugInfo;
|
return error.MissingDebugInfo;
|
||||||
} else if (self.prev_file - 1 >= self.file_entries.len) {
|
} else if (self.prev_file - 1 >= self.file_entries.len) {
|
||||||
return error.InvalidDebugInfo;
|
return error.InvalidDebugInfo;
|
||||||
} else {
|
} else &self.file_entries.items[self.prev_file - 1];
|
||||||
&self.file_entries.items[self.prev_file - 1]
|
|
||||||
};
|
|
||||||
const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
|
const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
|
||||||
return error.InvalidDebugInfo;
|
return error.InvalidDebugInfo;
|
||||||
} else {
|
} else self.include_dirs[file_entry.dir_index];
|
||||||
self.include_dirs[file_entry.dir_index]
|
|
||||||
};
|
|
||||||
const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
|
const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
|
||||||
%defer self.file_entries.allocator.free(file_name);
|
%defer self.file_entries.allocator.free(file_name);
|
||||||
return LineInfo {
|
return LineInfo {
|
||||||
@ -494,28 +491,21 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
|
fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
|
||||||
FormValue { .Const = Constant {
|
return FormValue { .Const = Constant {
|
||||||
.signed = signed,
|
.signed = signed,
|
||||||
.payload = %return readAllocBytes(allocator, in_stream, size),
|
.payload = %return readAllocBytes(allocator, in_stream, size),
|
||||||
}}
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
|
fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
|
||||||
return if (is_64) {
|
return if (is_64) %return in_stream.readIntLe(u64)
|
||||||
%return in_stream.readIntLe(u64)
|
else u64(%return in_stream.readIntLe(u32)) ;
|
||||||
} else {
|
|
||||||
u64(%return in_stream.readIntLe(u32))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
|
fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
|
||||||
return if (@sizeOf(usize) == 4) {
|
return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32))
|
||||||
u64(%return in_stream.readIntLe(u32))
|
else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64)
|
||||||
} else if (@sizeOf(usize) == 8) {
|
else unreachable;
|
||||||
%return in_stream.readIntLe(u64)
|
|
||||||
} else {
|
|
||||||
unreachable;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
|
fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
|
||||||
@ -534,9 +524,9 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
|
|||||||
DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
|
DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
|
||||||
DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
|
DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
|
||||||
DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
|
DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
|
||||||
DW.FORM_block => {
|
DW.FORM_block => x: {
|
||||||
const block_len = %return readULeb128(in_stream);
|
const block_len = %return readULeb128(in_stream);
|
||||||
parseFormValueBlockLen(allocator, in_stream, block_len)
|
return parseFormValueBlockLen(allocator, in_stream, block_len);
|
||||||
},
|
},
|
||||||
DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
|
DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
|
||||||
DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
|
DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
|
||||||
@ -545,7 +535,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
|
|||||||
DW.FORM_udata, DW.FORM_sdata => {
|
DW.FORM_udata, DW.FORM_sdata => {
|
||||||
const block_len = %return readULeb128(in_stream);
|
const block_len = %return readULeb128(in_stream);
|
||||||
const signed = form_id == DW.FORM_sdata;
|
const signed = form_id == DW.FORM_sdata;
|
||||||
parseFormValueConstant(allocator, in_stream, signed, block_len)
|
return parseFormValueConstant(allocator, in_stream, signed, block_len);
|
||||||
},
|
},
|
||||||
DW.FORM_exprloc => {
|
DW.FORM_exprloc => {
|
||||||
const size = %return readULeb128(in_stream);
|
const size = %return readULeb128(in_stream);
|
||||||
@ -562,7 +552,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
|
|||||||
DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
|
DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
|
||||||
DW.FORM_ref_udata => {
|
DW.FORM_ref_udata => {
|
||||||
const ref_len = %return readULeb128(in_stream);
|
const ref_len = %return readULeb128(in_stream);
|
||||||
parseFormValueRefLen(allocator, in_stream, ref_len)
|
return parseFormValueRefLen(allocator, in_stream, ref_len);
|
||||||
},
|
},
|
||||||
|
|
||||||
DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||||
@ -572,10 +562,10 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
|
|||||||
DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||||
DW.FORM_indirect => {
|
DW.FORM_indirect => {
|
||||||
const child_form_id = %return readULeb128(in_stream);
|
const child_form_id = %return readULeb128(in_stream);
|
||||||
parseFormValue(allocator, in_stream, child_form_id, is_64)
|
return parseFormValue(allocator, in_stream, child_form_id, is_64);
|
||||||
},
|
},
|
||||||
else => error.InvalidDebugInfo,
|
else => error.InvalidDebugInfo,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
|
fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
|
||||||
@ -852,11 +842,9 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
|
|||||||
const version = %return in_stream.readInt(st.elf.endian, u16);
|
const version = %return in_stream.readInt(st.elf.endian, u16);
|
||||||
if (version < 2 or version > 5) return error.InvalidDebugInfo;
|
if (version < 2 or version > 5) return error.InvalidDebugInfo;
|
||||||
|
|
||||||
const debug_abbrev_offset = if (is_64) {
|
const debug_abbrev_offset =
|
||||||
%return in_stream.readInt(st.elf.endian, u64)
|
if (is_64) %return in_stream.readInt(st.elf.endian, u64)
|
||||||
} else {
|
else %return in_stream.readInt(st.elf.endian, u32);
|
||||||
%return in_stream.readInt(st.elf.endian, u32)
|
|
||||||
};
|
|
||||||
|
|
||||||
const address_size = %return in_stream.readByte();
|
const address_size = %return in_stream.readByte();
|
||||||
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
||||||
@ -872,28 +860,28 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
|
|||||||
if (compile_unit_die.tag_id != DW.TAG_compile_unit)
|
if (compile_unit_die.tag_id != DW.TAG_compile_unit)
|
||||||
return error.InvalidDebugInfo;
|
return error.InvalidDebugInfo;
|
||||||
|
|
||||||
const pc_range = {
|
const pc_range = x: {
|
||||||
if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
|
if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
|
||||||
if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
|
if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
|
||||||
const pc_end = switch (*high_pc_value) {
|
const pc_end = switch (*high_pc_value) {
|
||||||
FormValue.Address => |value| value,
|
FormValue.Address => |value| value,
|
||||||
FormValue.Const => |value| {
|
FormValue.Const => |value| b: {
|
||||||
const offset = %return value.asUnsignedLe();
|
const offset = %return value.asUnsignedLe();
|
||||||
low_pc + offset
|
break :b (low_pc + offset);
|
||||||
},
|
},
|
||||||
else => return error.InvalidDebugInfo,
|
else => return error.InvalidDebugInfo,
|
||||||
};
|
};
|
||||||
PcRange {
|
break :x PcRange {
|
||||||
.start = low_pc,
|
.start = low_pc,
|
||||||
.end = pc_end,
|
.end = pc_end,
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
null
|
break :x null;
|
||||||
}
|
}
|
||||||
} else |err| {
|
} else |err| {
|
||||||
if (err != error.MissingDebugInfo)
|
if (err != error.MissingDebugInfo)
|
||||||
return err;
|
return err;
|
||||||
null
|
break :x null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -949,12 +937,12 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUn
|
|||||||
fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
|
fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
|
||||||
const first_32_bits = %return in_stream.readIntLe(u32);
|
const first_32_bits = %return in_stream.readIntLe(u32);
|
||||||
*is_64 = (first_32_bits == 0xffffffff);
|
*is_64 = (first_32_bits == 0xffffffff);
|
||||||
return if (*is_64) {
|
if (*is_64) {
|
||||||
%return in_stream.readIntLe(u64)
|
return in_stream.readIntLe(u64);
|
||||||
} else {
|
} else {
|
||||||
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
|
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
|
||||||
u64(first_32_bits)
|
return u64(first_32_bits);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readULeb128(in_stream: &io.InStream) -> %u64 {
|
fn readULeb128(in_stream: &io.InStream) -> %u64 {
|
||||||
|
@ -2,15 +2,15 @@ const mem = @import("mem.zig");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
pub fn swapIfLe(comptime T: type, x: T) -> T {
|
pub fn swapIfLe(comptime T: type, x: T) -> T {
|
||||||
swapIf(false, T, x)
|
return swapIf(false, T, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swapIfBe(comptime T: type, x: T) -> T {
|
pub fn swapIfBe(comptime T: type, x: T) -> T {
|
||||||
swapIf(true, T, x)
|
return swapIf(true, T, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {
|
pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {
|
||||||
if (builtin.endian == endian) swap(T, x) else x
|
return if (builtin.endian == endian) swap(T, x) else x;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swap(comptime T: type, x: T) -> T {
|
pub fn swap(comptime T: type, x: T) -> T {
|
||||||
|
@ -439,10 +439,10 @@ const Slab = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn slab(str: []const u8, exp: i32) -> Slab {
|
fn slab(str: []const u8, exp: i32) -> Slab {
|
||||||
Slab {
|
return Slab {
|
||||||
.str = str,
|
.str = str,
|
||||||
.exp = exp,
|
.exp = exp,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const enum3_data = []Slab {
|
pub const enum3_data = []Slab {
|
||||||
|
@ -251,11 +251,10 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons
|
|||||||
%return output(context, float_decimal.digits[0..1]);
|
%return output(context, float_decimal.digits[0..1]);
|
||||||
%return output(context, ".");
|
%return output(context, ".");
|
||||||
if (float_decimal.digits.len > 1) {
|
if (float_decimal.digits.len > 1) {
|
||||||
const num_digits = if (@typeOf(value) == f32) {
|
const num_digits = if (@typeOf(value) == f32)
|
||||||
math.min(usize(9), float_decimal.digits.len)
|
math.min(usize(9), float_decimal.digits.len)
|
||||||
} else {
|
else
|
||||||
float_decimal.digits.len
|
float_decimal.digits.len;
|
||||||
};
|
|
||||||
%return output(context, float_decimal.digits[1 .. num_digits]);
|
%return output(context, float_decimal.digits[1 .. num_digits]);
|
||||||
} else {
|
} else {
|
||||||
%return output(context, "0");
|
%return output(context, "0");
|
||||||
|
@ -12,7 +12,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
|||||||
comptime hash: fn(key: K)->u32,
|
comptime hash: fn(key: K)->u32,
|
||||||
comptime eql: fn(a: K, b: K)->bool) -> type
|
comptime eql: fn(a: K, b: K)->bool) -> type
|
||||||
{
|
{
|
||||||
struct {
|
return struct {
|
||||||
entries: []Entry,
|
entries: []Entry,
|
||||||
size: usize,
|
size: usize,
|
||||||
max_distance_from_start_index: usize,
|
max_distance_from_start_index: usize,
|
||||||
@ -51,19 +51,19 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable // no next item
|
unreachable; // no next item
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: &Allocator) -> Self {
|
pub fn init(allocator: &Allocator) -> Self {
|
||||||
Self {
|
return Self {
|
||||||
.entries = []Entry{},
|
.entries = []Entry{},
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.size = 0,
|
.size = 0,
|
||||||
.max_distance_from_start_index = 0,
|
.max_distance_from_start_index = 0,
|
||||||
// it doesn't actually matter what we set this to since we use wrapping integer arithmetic
|
// it doesn't actually matter what we set this to since we use wrapping integer arithmetic
|
||||||
.modification_count = undefined,
|
.modification_count = undefined,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(hm: &Self) {
|
pub fn deinit(hm: &Self) {
|
||||||
@ -133,7 +133,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
|||||||
entry.distance_from_start_index -= 1;
|
entry.distance_from_start_index -= 1;
|
||||||
entry = next_entry;
|
entry = next_entry;
|
||||||
}
|
}
|
||||||
unreachable // shifting everything in the table
|
unreachable; // shifting everything in the table
|
||||||
}}
|
}}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
|||||||
const start_index = hm.keyToIndex(key);
|
const start_index = hm.keyToIndex(key);
|
||||||
var roll_over: usize = 0;
|
var roll_over: usize = 0;
|
||||||
var distance_from_start_index: usize = 0;
|
var distance_from_start_index: usize = 0;
|
||||||
while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1}) {
|
while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1;}) {
|
||||||
const index = (start_index + roll_over) % hm.entries.len;
|
const index = (start_index + roll_over) % hm.entries.len;
|
||||||
const entry = &hm.entries[index];
|
const entry = &hm.entries[index];
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
|||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
unreachable // put into a full map
|
unreachable; // put into a full map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internalGet(hm: &Self, key: K) -> ?&Entry {
|
fn internalGet(hm: &Self, key: K) -> ?&Entry {
|
||||||
@ -228,7 +228,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
|||||||
fn keyToIndex(hm: &Self, key: K) -> usize {
|
fn keyToIndex(hm: &Self, key: K) -> usize {
|
||||||
return usize(hash(key)) % hm.entries.len;
|
return usize(hash(key)) % hm.entries.len;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "basicHashMapTest" {
|
test "basicHashMapTest" {
|
||||||
@ -251,9 +251,9 @@ test "basicHashMapTest" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn hash_i32(x: i32) -> u32 {
|
fn hash_i32(x: i32) -> u32 {
|
||||||
@bitCast(u32, x)
|
return @bitCast(u32, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eql_i32(a: i32, b: i32) -> bool {
|
fn eql_i32(a: i32, b: i32) -> bool {
|
||||||
a == b
|
return a == b;
|
||||||
}
|
}
|
||||||
|
13
std/heap.zig
13
std/heap.zig
@ -17,22 +17,21 @@ pub var c_allocator = Allocator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 {
|
fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 {
|
||||||
if (c.malloc(usize(n))) |buf| {
|
return if (c.malloc(usize(n))) |buf|
|
||||||
@ptrCast(&u8, buf)[0..n]
|
@ptrCast(&u8, buf)[0..n]
|
||||||
} else {
|
else
|
||||||
error.OutOfMemory
|
error.OutOfMemory;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
|
fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
|
||||||
if (new_size <= old_mem.len) {
|
if (new_size <= old_mem.len) {
|
||||||
old_mem[0..new_size]
|
return old_mem[0..new_size];
|
||||||
} else {
|
} else {
|
||||||
const old_ptr = @ptrCast(&c_void, old_mem.ptr);
|
const old_ptr = @ptrCast(&c_void, old_mem.ptr);
|
||||||
if (c.realloc(old_ptr, usize(new_size))) |buf| {
|
if (c.realloc(old_ptr, usize(new_size))) |buf| {
|
||||||
@ptrCast(&u8, buf)[0..new_size]
|
return @ptrCast(&u8, buf)[0..new_size];
|
||||||
} else {
|
} else {
|
||||||
error.OutOfMemory
|
return error.OutOfMemory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
std/io.zig
29
std/io.zig
@ -50,35 +50,32 @@ error Unseekable;
|
|||||||
error EndOfFile;
|
error EndOfFile;
|
||||||
|
|
||||||
pub fn getStdErr() -> %File {
|
pub fn getStdErr() -> %File {
|
||||||
const handle = if (is_windows) {
|
const handle = if (is_windows)
|
||||||
%return os.windowsGetStdHandle(system.STD_ERROR_HANDLE)
|
%return os.windowsGetStdHandle(system.STD_ERROR_HANDLE)
|
||||||
} else if (is_posix) {
|
else if (is_posix)
|
||||||
system.STDERR_FILENO
|
system.STDERR_FILENO
|
||||||
} else {
|
else
|
||||||
unreachable
|
unreachable;
|
||||||
};
|
|
||||||
return File.openHandle(handle);
|
return File.openHandle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getStdOut() -> %File {
|
pub fn getStdOut() -> %File {
|
||||||
const handle = if (is_windows) {
|
const handle = if (is_windows)
|
||||||
%return os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE)
|
%return os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE)
|
||||||
} else if (is_posix) {
|
else if (is_posix)
|
||||||
system.STDOUT_FILENO
|
system.STDOUT_FILENO
|
||||||
} else {
|
else
|
||||||
unreachable
|
unreachable;
|
||||||
};
|
|
||||||
return File.openHandle(handle);
|
return File.openHandle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getStdIn() -> %File {
|
pub fn getStdIn() -> %File {
|
||||||
const handle = if (is_windows) {
|
const handle = if (is_windows)
|
||||||
%return os.windowsGetStdHandle(system.STD_INPUT_HANDLE)
|
%return os.windowsGetStdHandle(system.STD_INPUT_HANDLE)
|
||||||
} else if (is_posix) {
|
else if (is_posix)
|
||||||
system.STDIN_FILENO
|
system.STDIN_FILENO
|
||||||
} else {
|
else
|
||||||
unreachable
|
unreachable;
|
||||||
};
|
|
||||||
return File.openHandle(handle);
|
return File.openHandle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +258,7 @@ pub const File = struct {
|
|||||||
system.EBADF => error.BadFd,
|
system.EBADF => error.BadFd,
|
||||||
system.ENOMEM => error.SystemResources,
|
system.ENOMEM => error.SystemResources,
|
||||||
else => os.unexpectedErrorPosix(err),
|
else => os.unexpectedErrorPosix(err),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return usize(stat.size);
|
return usize(stat.size);
|
||||||
|
@ -5,7 +5,7 @@ const Allocator = mem.Allocator;
|
|||||||
|
|
||||||
/// Generic doubly linked list.
|
/// Generic doubly linked list.
|
||||||
pub fn LinkedList(comptime T: type) -> type {
|
pub fn LinkedList(comptime T: type) -> type {
|
||||||
struct {
|
return struct {
|
||||||
const Self = this;
|
const Self = this;
|
||||||
|
|
||||||
/// Node inside the linked list wrapping the actual data.
|
/// Node inside the linked list wrapping the actual data.
|
||||||
@ -15,11 +15,11 @@ pub fn LinkedList(comptime T: type) -> type {
|
|||||||
data: T,
|
data: T,
|
||||||
|
|
||||||
pub fn init(data: &const T) -> Node {
|
pub fn init(data: &const T) -> Node {
|
||||||
Node {
|
return Node {
|
||||||
.prev = null,
|
.prev = null,
|
||||||
.next = null,
|
.next = null,
|
||||||
.data = *data,
|
.data = *data,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,11 +32,11 @@ pub fn LinkedList(comptime T: type) -> type {
|
|||||||
/// Returns:
|
/// Returns:
|
||||||
/// An empty linked list.
|
/// An empty linked list.
|
||||||
pub fn init() -> Self {
|
pub fn init() -> Self {
|
||||||
Self {
|
return Self {
|
||||||
.first = null,
|
.first = null,
|
||||||
.last = null,
|
.last = null,
|
||||||
.len = 0,
|
.len = 0,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a new node after an existing one.
|
/// Insert a new node after an existing one.
|
||||||
@ -166,7 +166,7 @@ pub fn LinkedList(comptime T: type) -> type {
|
|||||||
/// Returns:
|
/// Returns:
|
||||||
/// A pointer to the new node.
|
/// A pointer to the new node.
|
||||||
pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node {
|
pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node {
|
||||||
allocator.create(Node)
|
return allocator.create(Node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deallocate a node.
|
/// Deallocate a node.
|
||||||
@ -191,7 +191,7 @@ pub fn LinkedList(comptime T: type) -> type {
|
|||||||
*node = Node.init(data);
|
*node = Node.init(data);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "basic linked list test" {
|
test "basic linked list test" {
|
||||||
|
@ -7,11 +7,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn acos(x: var) -> @typeOf(x) {
|
pub fn acos(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(acos32, x),
|
f32 => @inlineCall(acos32, x),
|
||||||
f64 => @inlineCall(acos64, x),
|
f64 => @inlineCall(acos64, x),
|
||||||
else => @compileError("acos not implemented for " ++ @typeName(T)),
|
else => @compileError("acos not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn r32(z: f32) -> f32 {
|
fn r32(z: f32) -> f32 {
|
||||||
@ -22,7 +22,7 @@ fn r32(z: f32) -> f32 {
|
|||||||
|
|
||||||
const p = z * (pS0 + z * (pS1 + z * pS2));
|
const p = z * (pS0 + z * (pS1 + z * pS2));
|
||||||
const q = 1.0 + z * qS1;
|
const q = 1.0 + z * qS1;
|
||||||
p / q
|
return p / q;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn acos32(x: f32) -> f32 {
|
fn acos32(x: f32) -> f32 {
|
||||||
@ -69,7 +69,7 @@ fn acos32(x: f32) -> f32 {
|
|||||||
const df = @bitCast(f32, jx & 0xFFFFF000);
|
const df = @bitCast(f32, jx & 0xFFFFF000);
|
||||||
const c = (z - df * df) / (s + df);
|
const c = (z - df * df) / (s + df);
|
||||||
const w = r32(z) * s + c;
|
const w = r32(z) * s + c;
|
||||||
2 * (df + w)
|
return 2 * (df + w);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn r64(z: f64) -> f64 {
|
fn r64(z: f64) -> f64 {
|
||||||
@ -86,7 +86,7 @@ fn r64(z: f64) -> f64 {
|
|||||||
|
|
||||||
const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
|
const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
|
||||||
const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
|
const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
|
||||||
p / q
|
return p / q;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn acos64(x: f64) -> f64 {
|
fn acos64(x: f64) -> f64 {
|
||||||
@ -138,7 +138,7 @@ fn acos64(x: f64) -> f64 {
|
|||||||
const df = @bitCast(f64, jx & 0xFFFFFFFF00000000);
|
const df = @bitCast(f64, jx & 0xFFFFFFFF00000000);
|
||||||
const c = (z - df * df) / (s + df);
|
const c = (z - df * df) / (s + df);
|
||||||
const w = r64(z) * s + c;
|
const w = r64(z) * s + c;
|
||||||
2 * (df + w)
|
return 2 * (df + w);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.acos" {
|
test "math.acos" {
|
||||||
|
@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn acosh(x: var) -> @typeOf(x) {
|
pub fn acosh(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(acosh32, x),
|
f32 => @inlineCall(acosh32, x),
|
||||||
f64 => @inlineCall(acosh64, x),
|
f64 => @inlineCall(acosh64, x),
|
||||||
else => @compileError("acosh not implemented for " ++ @typeName(T)),
|
else => @compileError("acosh not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// acosh(x) = log(x + sqrt(x * x - 1))
|
// acosh(x) = log(x + sqrt(x * x - 1))
|
||||||
@ -23,15 +23,15 @@ fn acosh32(x: f32) -> f32 {
|
|||||||
|
|
||||||
// |x| < 2, invalid if x < 1 or nan
|
// |x| < 2, invalid if x < 1 or nan
|
||||||
if (i < 0x3F800000 + (1 << 23)) {
|
if (i < 0x3F800000 + (1 << 23)) {
|
||||||
math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)))
|
return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)));
|
||||||
}
|
}
|
||||||
// |x| < 0x1p12
|
// |x| < 0x1p12
|
||||||
else if (i < 0x3F800000 + (12 << 23)) {
|
else if (i < 0x3F800000 + (12 << 23)) {
|
||||||
math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)))
|
return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)));
|
||||||
}
|
}
|
||||||
// |x| >= 0x1p12
|
// |x| >= 0x1p12
|
||||||
else {
|
else {
|
||||||
math.ln(x) + 0.693147180559945309417232121458176568
|
return math.ln(x) + 0.693147180559945309417232121458176568;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,15 +41,15 @@ fn acosh64(x: f64) -> f64 {
|
|||||||
|
|
||||||
// |x| < 2, invalid if x < 1 or nan
|
// |x| < 2, invalid if x < 1 or nan
|
||||||
if (e < 0x3FF + 1) {
|
if (e < 0x3FF + 1) {
|
||||||
math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)))
|
return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)));
|
||||||
}
|
}
|
||||||
// |x| < 0x1p26
|
// |x| < 0x1p26
|
||||||
else if (e < 0x3FF + 26) {
|
else if (e < 0x3FF + 26) {
|
||||||
math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)))
|
return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)));
|
||||||
}
|
}
|
||||||
// |x| >= 0x1p26 or nan
|
// |x| >= 0x1p26 or nan
|
||||||
else {
|
else {
|
||||||
math.ln(x) + 0.693147180559945309417232121458176568
|
return math.ln(x) + 0.693147180559945309417232121458176568;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn asin(x: var) -> @typeOf(x) {
|
pub fn asin(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(asin32, x),
|
f32 => @inlineCall(asin32, x),
|
||||||
f64 => @inlineCall(asin64, x),
|
f64 => @inlineCall(asin64, x),
|
||||||
else => @compileError("asin not implemented for " ++ @typeName(T)),
|
else => @compileError("asin not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn r32(z: f32) -> f32 {
|
fn r32(z: f32) -> f32 {
|
||||||
@ -23,7 +23,7 @@ fn r32(z: f32) -> f32 {
|
|||||||
|
|
||||||
const p = z * (pS0 + z * (pS1 + z * pS2));
|
const p = z * (pS0 + z * (pS1 + z * pS2));
|
||||||
const q = 1.0 + z * qS1;
|
const q = 1.0 + z * qS1;
|
||||||
p / q
|
return p / q;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asin32(x: f32) -> f32 {
|
fn asin32(x: f32) -> f32 {
|
||||||
@ -58,9 +58,9 @@ fn asin32(x: f32) -> f32 {
|
|||||||
const fx = pio2 - 2 * (s + s * r32(z));
|
const fx = pio2 - 2 * (s + s * r32(z));
|
||||||
|
|
||||||
if (hx >> 31 != 0) {
|
if (hx >> 31 != 0) {
|
||||||
-fx
|
return -fx;
|
||||||
} else {
|
} else {
|
||||||
fx
|
return fx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ fn r64(z: f64) -> f64 {
|
|||||||
|
|
||||||
const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
|
const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
|
||||||
const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
|
const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
|
||||||
p / q
|
return p / q;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asin64(x: f64) -> f64 {
|
fn asin64(x: f64) -> f64 {
|
||||||
@ -119,7 +119,7 @@ fn asin64(x: f64) -> f64 {
|
|||||||
|
|
||||||
// |x| > 0.975
|
// |x| > 0.975
|
||||||
if (ix >= 0x3FEF3333) {
|
if (ix >= 0x3FEF3333) {
|
||||||
fx = pio2_hi - 2 * (s + s * r)
|
fx = pio2_hi - 2 * (s + s * r);
|
||||||
} else {
|
} else {
|
||||||
const jx = @bitCast(u64, s);
|
const jx = @bitCast(u64, s);
|
||||||
const df = @bitCast(f64, jx & 0xFFFFFFFF00000000);
|
const df = @bitCast(f64, jx & 0xFFFFFFFF00000000);
|
||||||
@ -128,9 +128,9 @@ fn asin64(x: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hx >> 31 != 0) {
|
if (hx >> 31 != 0) {
|
||||||
-fx
|
return -fx;
|
||||||
} else {
|
} else {
|
||||||
fx
|
return fx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn asinh(x: var) -> @typeOf(x) {
|
pub fn asinh(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(asinh32, x),
|
f32 => @inlineCall(asinh32, x),
|
||||||
f64 => @inlineCall(asinh64, x),
|
f64 => @inlineCall(asinh64, x),
|
||||||
else => @compileError("asinh not implemented for " ++ @typeName(T)),
|
else => @compileError("asinh not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// asinh(x) = sign(x) * log(|x| + sqrt(x * x + 1)) ~= x - x^3/6 + o(x^5)
|
// asinh(x) = sign(x) * log(|x| + sqrt(x * x + 1)) ~= x - x^3/6 + o(x^5)
|
||||||
@ -46,7 +46,7 @@ fn asinh32(x: f32) -> f32 {
|
|||||||
math.forceEval(x + 0x1.0p120);
|
math.forceEval(x + 0x1.0p120);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s != 0) -rx else rx
|
return if (s != 0) -rx else rx;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asinh64(x: f64) -> f64 {
|
fn asinh64(x: f64) -> f64 {
|
||||||
@ -77,7 +77,7 @@ fn asinh64(x: f64) -> f64 {
|
|||||||
math.forceEval(x + 0x1.0p120);
|
math.forceEval(x + 0x1.0p120);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s != 0) -rx else rx
|
return if (s != 0) -rx else rx;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.asinh" {
|
test "math.asinh" {
|
||||||
|
@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn atan(x: var) -> @typeOf(x) {
|
pub fn atan(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(atan32, x),
|
f32 => @inlineCall(atan32, x),
|
||||||
f64 => @inlineCall(atan64, x),
|
f64 => @inlineCall(atan64, x),
|
||||||
else => @compileError("atan not implemented for " ++ @typeName(T)),
|
else => @compileError("atan not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn atan32(x_: f32) -> f32 {
|
fn atan32(x_: f32) -> f32 {
|
||||||
@ -100,10 +100,10 @@ fn atan32(x_: f32) -> f32 {
|
|||||||
const s2 = w * (aT[1] + w * aT[3]);
|
const s2 = w * (aT[1] + w * aT[3]);
|
||||||
|
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
x - x * (s1 + s2)
|
return x - x * (s1 + s2);
|
||||||
} else {
|
} else {
|
||||||
const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x);
|
const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x);
|
||||||
if (sign != 0) -zz else zz
|
return if (sign != 0) -zz else zz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,10 +199,10 @@ fn atan64(x_: f64) -> f64 {
|
|||||||
const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9]))));
|
const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9]))));
|
||||||
|
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
x - x * (s1 + s2)
|
return x - x * (s1 + s2);
|
||||||
} else {
|
} else {
|
||||||
const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x);
|
const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x);
|
||||||
if (sign != 0) -zz else zz
|
return if (sign != 0) -zz else zz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,11 +22,11 @@ const math = @import("index.zig");
|
|||||||
const assert = @import("../debug.zig").assert;
|
const assert = @import("../debug.zig").assert;
|
||||||
|
|
||||||
fn atan2(comptime T: type, x: T, y: T) -> T {
|
fn atan2(comptime T: type, x: T, y: T) -> T {
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(atan2_32, x, y),
|
f32 => @inlineCall(atan2_32, x, y),
|
||||||
f64 => @inlineCall(atan2_64, x, y),
|
f64 => @inlineCall(atan2_64, x, y),
|
||||||
else => @compileError("atan2 not implemented for " ++ @typeName(T)),
|
else => @compileError("atan2 not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn atan2_32(y: f32, x: f32) -> f32 {
|
fn atan2_32(y: f32, x: f32) -> f32 {
|
||||||
@ -97,11 +97,11 @@ fn atan2_32(y: f32, x: f32) -> f32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// z = atan(|y / x|) with correct underflow
|
// z = atan(|y / x|) with correct underflow
|
||||||
var z = {
|
var z = z: {
|
||||||
if ((m & 2) != 0 and iy + (26 << 23) < ix) {
|
if ((m & 2) != 0 and iy + (26 << 23) < ix) {
|
||||||
0.0
|
break :z 0.0;
|
||||||
} else {
|
} else {
|
||||||
math.atan(math.fabs(y / x))
|
break :z math.atan(math.fabs(y / x));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -187,11 +187,11 @@ fn atan2_64(y: f64, x: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// z = atan(|y / x|) with correct underflow
|
// z = atan(|y / x|) with correct underflow
|
||||||
var z = {
|
var z = z: {
|
||||||
if ((m & 2) != 0 and iy +% (64 << 20) < ix) {
|
if ((m & 2) != 0 and iy +% (64 << 20) < ix) {
|
||||||
0.0
|
break :z 0.0;
|
||||||
} else {
|
} else {
|
||||||
math.atan(math.fabs(y / x))
|
break :z math.atan(math.fabs(y / x));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn atanh(x: var) -> @typeOf(x) {
|
pub fn atanh(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(atanh_32, x),
|
f32 => @inlineCall(atanh_32, x),
|
||||||
f64 => @inlineCall(atanh_64, x),
|
f64 => @inlineCall(atanh_64, x),
|
||||||
else => @compileError("atanh not implemented for " ++ @typeName(T)),
|
else => @compileError("atanh not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// atanh(x) = log((1 + x) / (1 - x)) / 2 = log1p(2x / (1 - x)) / 2 ~= x + x^3 / 3 + o(x^5)
|
// atanh(x) = log((1 + x) / (1 - x)) / 2 = log1p(2x / (1 - x)) / 2 ~= x + x^3 / 3 + o(x^5)
|
||||||
@ -32,7 +32,7 @@ fn atanh_32(x: f32) -> f32 {
|
|||||||
if (u < 0x3F800000 - (32 << 23)) {
|
if (u < 0x3F800000 - (32 << 23)) {
|
||||||
// underflow
|
// underflow
|
||||||
if (u < (1 << 23)) {
|
if (u < (1 << 23)) {
|
||||||
math.forceEval(y * y)
|
math.forceEval(y * y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// |x| < 0.5
|
// |x| < 0.5
|
||||||
@ -43,7 +43,7 @@ fn atanh_32(x: f32) -> f32 {
|
|||||||
y = 0.5 * math.log1p(2 * (y / (1 - y)));
|
y = 0.5 * math.log1p(2 * (y / (1 - y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s != 0) -y else y
|
return if (s != 0) -y else y;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn atanh_64(x: f64) -> f64 {
|
fn atanh_64(x: f64) -> f64 {
|
||||||
@ -72,7 +72,7 @@ fn atanh_64(x: f64) -> f64 {
|
|||||||
y = 0.5 * math.log1p(2 * (y / (1 - y)));
|
y = 0.5 * math.log1p(2 * (y / (1 - y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s != 0) -y else y
|
return if (s != 0) -y else y;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.atanh" {
|
test "math.atanh" {
|
||||||
|
@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn cbrt(x: var) -> @typeOf(x) {
|
pub fn cbrt(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(cbrt32, x),
|
f32 => @inlineCall(cbrt32, x),
|
||||||
f64 => @inlineCall(cbrt64, x),
|
f64 => @inlineCall(cbrt64, x),
|
||||||
else => @compileError("cbrt not implemented for " ++ @typeName(T)),
|
else => @compileError("cbrt not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cbrt32(x: f32) -> f32 {
|
fn cbrt32(x: f32) -> f32 {
|
||||||
@ -53,7 +53,7 @@ fn cbrt32(x: f32) -> f32 {
|
|||||||
r = t * t * t;
|
r = t * t * t;
|
||||||
t = t * (f64(x) + x + r) / (x + r + r);
|
t = t * (f64(x) + x + r) / (x + r + r);
|
||||||
|
|
||||||
f32(t)
|
return f32(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cbrt64(x: f64) -> f64 {
|
fn cbrt64(x: f64) -> f64 {
|
||||||
@ -109,7 +109,7 @@ fn cbrt64(x: f64) -> f64 {
|
|||||||
var w = t + t;
|
var w = t + t;
|
||||||
q = (q - t) / (w + q);
|
q = (q - t) / (w + q);
|
||||||
|
|
||||||
t + t * q
|
return t + t * q;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.cbrt" {
|
test "math.cbrt" {
|
||||||
|
@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn ceil(x: var) -> @typeOf(x) {
|
pub fn ceil(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(ceil32, x),
|
f32 => @inlineCall(ceil32, x),
|
||||||
f64 => @inlineCall(ceil64, x),
|
f64 => @inlineCall(ceil64, x),
|
||||||
else => @compileError("ceil not implemented for " ++ @typeName(T)),
|
else => @compileError("ceil not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ceil32(x: f32) -> f32 {
|
fn ceil32(x: f32) -> f32 {
|
||||||
@ -39,13 +39,13 @@ fn ceil32(x: f32) -> f32 {
|
|||||||
u += m;
|
u += m;
|
||||||
}
|
}
|
||||||
u &= ~m;
|
u &= ~m;
|
||||||
@bitCast(f32, u)
|
return @bitCast(f32, u);
|
||||||
} else {
|
} else {
|
||||||
math.forceEval(x + 0x1.0p120);
|
math.forceEval(x + 0x1.0p120);
|
||||||
if (u >> 31 != 0) {
|
if (u >> 31 != 0) {
|
||||||
return -0.0;
|
return -0.0;
|
||||||
} else {
|
} else {
|
||||||
1.0
|
return 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,14 +70,14 @@ fn ceil64(x: f64) -> f64 {
|
|||||||
if (e <= 0x3FF-1) {
|
if (e <= 0x3FF-1) {
|
||||||
math.forceEval(y);
|
math.forceEval(y);
|
||||||
if (u >> 63 != 0) {
|
if (u >> 63 != 0) {
|
||||||
return -0.0; // Compiler requires return.
|
return -0.0;
|
||||||
} else {
|
} else {
|
||||||
1.0
|
return 1.0;
|
||||||
}
|
}
|
||||||
} else if (y < 0) {
|
} else if (y < 0) {
|
||||||
x + y + 1
|
return x + y + 1;
|
||||||
} else {
|
} else {
|
||||||
x + y
|
return x + y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@ const math = @import("index.zig");
|
|||||||
const assert = @import("../debug.zig").assert;
|
const assert = @import("../debug.zig").assert;
|
||||||
|
|
||||||
pub fn copysign(comptime T: type, x: T, y: T) -> T {
|
pub fn copysign(comptime T: type, x: T, y: T) -> T {
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(copysign32, x, y),
|
f32 => @inlineCall(copysign32, x, y),
|
||||||
f64 => @inlineCall(copysign64, x, y),
|
f64 => @inlineCall(copysign64, x, y),
|
||||||
else => @compileError("copysign not implemented for " ++ @typeName(T)),
|
else => @compileError("copysign not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copysign32(x: f32, y: f32) -> f32 {
|
fn copysign32(x: f32, y: f32) -> f32 {
|
||||||
@ -15,7 +15,7 @@ fn copysign32(x: f32, y: f32) -> f32 {
|
|||||||
|
|
||||||
const h1 = ux & (@maxValue(u32) / 2);
|
const h1 = ux & (@maxValue(u32) / 2);
|
||||||
const h2 = uy & (u32(1) << 31);
|
const h2 = uy & (u32(1) << 31);
|
||||||
@bitCast(f32, h1 | h2)
|
return @bitCast(f32, h1 | h2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copysign64(x: f64, y: f64) -> f64 {
|
fn copysign64(x: f64, y: f64) -> f64 {
|
||||||
@ -24,7 +24,7 @@ fn copysign64(x: f64, y: f64) -> f64 {
|
|||||||
|
|
||||||
const h1 = ux & (@maxValue(u64) / 2);
|
const h1 = ux & (@maxValue(u64) / 2);
|
||||||
const h2 = uy & (u64(1) << 63);
|
const h2 = uy & (u64(1) << 63);
|
||||||
@bitCast(f64, h1 | h2)
|
return @bitCast(f64, h1 | h2);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.copysign" {
|
test "math.copysign" {
|
||||||
|
@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn cos(x: var) -> @typeOf(x) {
|
pub fn cos(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(cos32, x),
|
f32 => @inlineCall(cos32, x),
|
||||||
f64 => @inlineCall(cos64, x),
|
f64 => @inlineCall(cos64, x),
|
||||||
else => @compileError("cos not implemented for " ++ @typeName(T)),
|
else => @compileError("cos not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// sin polynomial coefficients
|
// sin polynomial coefficients
|
||||||
@ -73,18 +73,18 @@ fn cos32(x_: f32) -> f32 {
|
|||||||
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
||||||
const w = z * z;
|
const w = z * z;
|
||||||
|
|
||||||
const r = {
|
const r = r: {
|
||||||
if (j == 1 or j == 2) {
|
if (j == 1 or j == 2) {
|
||||||
z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))))
|
break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
|
||||||
} else {
|
} else {
|
||||||
1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))))
|
break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sign) {
|
if (sign) {
|
||||||
-r
|
return -r;
|
||||||
} else {
|
} else {
|
||||||
r
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,18 +124,18 @@ fn cos64(x_: f64) -> f64 {
|
|||||||
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
||||||
const w = z * z;
|
const w = z * z;
|
||||||
|
|
||||||
const r = {
|
const r = r: {
|
||||||
if (j == 1 or j == 2) {
|
if (j == 1 or j == 2) {
|
||||||
z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))))
|
break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
|
||||||
} else {
|
} else {
|
||||||
1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))))
|
break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sign) {
|
if (sign) {
|
||||||
-r
|
return -r;
|
||||||
} else {
|
} else {
|
||||||
r
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn cosh(x: var) -> @typeOf(x) {
|
pub fn cosh(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(cosh32, x),
|
f32 => @inlineCall(cosh32, x),
|
||||||
f64 => @inlineCall(cosh64, x),
|
f64 => @inlineCall(cosh64, x),
|
||||||
else => @compileError("cosh not implemented for " ++ @typeName(T)),
|
else => @compileError("cosh not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// cosh(x) = (exp(x) + 1 / exp(x)) / 2
|
// cosh(x) = (exp(x) + 1 / exp(x)) / 2
|
||||||
@ -43,7 +43,7 @@ fn cosh32(x: f32) -> f32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// |x| > log(FLT_MAX) or nan
|
// |x| > log(FLT_MAX) or nan
|
||||||
expo2(ax)
|
return expo2(ax);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cosh64(x: f64) -> f64 {
|
fn cosh64(x: f64) -> f64 {
|
||||||
@ -76,7 +76,7 @@ fn cosh64(x: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// |x| > log(CBL_MAX) or nan
|
// |x| > log(CBL_MAX) or nan
|
||||||
expo2(ax)
|
return expo2(ax);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.cosh" {
|
test "math.cosh" {
|
||||||
|
@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn exp(x: var) -> @typeOf(x) {
|
pub fn exp(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(exp32, x),
|
f32 => @inlineCall(exp32, x),
|
||||||
f64 => @inlineCall(exp64, x),
|
f64 => @inlineCall(exp64, x),
|
||||||
else => @compileError("exp not implemented for " ++ @typeName(T)),
|
else => @compileError("exp not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exp32(x_: f32) -> f32 {
|
fn exp32(x_: f32) -> f32 {
|
||||||
@ -86,9 +86,9 @@ fn exp32(x_: f32) -> f32 {
|
|||||||
const y = 1 + (x * c / (2 - c) - lo + hi);
|
const y = 1 + (x * c / (2 - c) - lo + hi);
|
||||||
|
|
||||||
if (k == 0) {
|
if (k == 0) {
|
||||||
y
|
return y;
|
||||||
} else {
|
} else {
|
||||||
math.scalbn(y, k)
|
return math.scalbn(y, k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +172,9 @@ fn exp64(x_: f64) -> f64 {
|
|||||||
const y = 1 + (x * c / (2 - c) - lo + hi);
|
const y = 1 + (x * c / (2 - c) - lo + hi);
|
||||||
|
|
||||||
if (k == 0) {
|
if (k == 0) {
|
||||||
y
|
return y;
|
||||||
} else {
|
} else {
|
||||||
math.scalbn(y, k)
|
return math.scalbn(y, k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn exp2(x: var) -> @typeOf(x) {
|
pub fn exp2(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(exp2_32, x),
|
f32 => @inlineCall(exp2_32, x),
|
||||||
f64 => @inlineCall(exp2_64, x),
|
f64 => @inlineCall(exp2_64, x),
|
||||||
else => @compileError("exp2 not implemented for " ++ @typeName(T)),
|
else => @compileError("exp2 not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const exp2ft = []const f64 {
|
const exp2ft = []const f64 {
|
||||||
@ -88,7 +88,7 @@ fn exp2_32(x: f32) -> f32 {
|
|||||||
var r: f64 = exp2ft[i0];
|
var r: f64 = exp2ft[i0];
|
||||||
const t: f64 = r * z;
|
const t: f64 = r * z;
|
||||||
r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4);
|
r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4);
|
||||||
f32(r * uk)
|
return f32(r * uk);
|
||||||
}
|
}
|
||||||
|
|
||||||
const exp2dt = []f64 {
|
const exp2dt = []f64 {
|
||||||
@ -414,7 +414,7 @@ fn exp2_64(x: f64) -> f64 {
|
|||||||
z -= exp2dt[2 * i0 + 1];
|
z -= exp2dt[2 * i0 + 1];
|
||||||
const r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
|
const r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
|
||||||
|
|
||||||
math.scalbn(r, ik)
|
return math.scalbn(r, ik);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.exp2" {
|
test "math.exp2" {
|
||||||
|
@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn expm1(x: var) -> @typeOf(x) {
|
pub fn expm1(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(expm1_32, x),
|
f32 => @inlineCall(expm1_32, x),
|
||||||
f64 => @inlineCall(expm1_64, x),
|
f64 => @inlineCall(expm1_64, x),
|
||||||
else => @compileError("exp1m not implemented for " ++ @typeName(T)),
|
else => @compileError("exp1m not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expm1_32(x_: f32) -> f32 {
|
fn expm1_32(x_: f32) -> f32 {
|
||||||
|
@ -2,11 +2,11 @@ const math = @import("index.zig");
|
|||||||
|
|
||||||
pub fn expo2(x: var) -> @typeOf(x) {
|
pub fn expo2(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => expo2f(x),
|
f32 => expo2f(x),
|
||||||
f64 => expo2d(x),
|
f64 => expo2d(x),
|
||||||
else => @compileError("expo2 not implemented for " ++ @typeName(T)),
|
else => @compileError("expo2 not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expo2f(x: f32) -> f32 {
|
fn expo2f(x: f32) -> f32 {
|
||||||
@ -15,7 +15,7 @@ fn expo2f(x: f32) -> f32 {
|
|||||||
|
|
||||||
const u = (0x7F + k / 2) << 23;
|
const u = (0x7F + k / 2) << 23;
|
||||||
const scale = @bitCast(f32, u);
|
const scale = @bitCast(f32, u);
|
||||||
math.exp(x - kln2) * scale * scale
|
return math.exp(x - kln2) * scale * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expo2d(x: f64) -> f64 {
|
fn expo2d(x: f64) -> f64 {
|
||||||
@ -24,5 +24,5 @@ fn expo2d(x: f64) -> f64 {
|
|||||||
|
|
||||||
const u = (0x3FF + k / 2) << 20;
|
const u = (0x3FF + k / 2) << 20;
|
||||||
const scale = @bitCast(f64, u64(u) << 32);
|
const scale = @bitCast(f64, u64(u) << 32);
|
||||||
math.exp(x - kln2) * scale * scale
|
return math.exp(x - kln2) * scale * scale;
|
||||||
}
|
}
|
||||||
|
@ -8,23 +8,23 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn fabs(x: var) -> @typeOf(x) {
|
pub fn fabs(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(fabs32, x),
|
f32 => @inlineCall(fabs32, x),
|
||||||
f64 => @inlineCall(fabs64, x),
|
f64 => @inlineCall(fabs64, x),
|
||||||
else => @compileError("fabs not implemented for " ++ @typeName(T)),
|
else => @compileError("fabs not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fabs32(x: f32) -> f32 {
|
fn fabs32(x: f32) -> f32 {
|
||||||
var u = @bitCast(u32, x);
|
var u = @bitCast(u32, x);
|
||||||
u &= 0x7FFFFFFF;
|
u &= 0x7FFFFFFF;
|
||||||
@bitCast(f32, u)
|
return @bitCast(f32, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fabs64(x: f64) -> f64 {
|
fn fabs64(x: f64) -> f64 {
|
||||||
var u = @bitCast(u64, x);
|
var u = @bitCast(u64, x);
|
||||||
u &= @maxValue(u64) >> 1;
|
u &= @maxValue(u64) >> 1;
|
||||||
@bitCast(f64, u)
|
return @bitCast(f64, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.fabs" {
|
test "math.fabs" {
|
||||||
|
@ -10,11 +10,11 @@ const math = @import("index.zig");
|
|||||||
|
|
||||||
pub fn floor(x: var) -> @typeOf(x) {
|
pub fn floor(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(floor32, x),
|
f32 => @inlineCall(floor32, x),
|
||||||
f64 => @inlineCall(floor64, x),
|
f64 => @inlineCall(floor64, x),
|
||||||
else => @compileError("floor not implemented for " ++ @typeName(T)),
|
else => @compileError("floor not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn floor32(x: f32) -> f32 {
|
fn floor32(x: f32) -> f32 {
|
||||||
@ -40,13 +40,13 @@ fn floor32(x: f32) -> f32 {
|
|||||||
if (u >> 31 != 0) {
|
if (u >> 31 != 0) {
|
||||||
u += m;
|
u += m;
|
||||||
}
|
}
|
||||||
@bitCast(f32, u & ~m)
|
return @bitCast(f32, u & ~m);
|
||||||
} else {
|
} else {
|
||||||
math.forceEval(x + 0x1.0p120);
|
math.forceEval(x + 0x1.0p120);
|
||||||
if (u >> 31 == 0) {
|
if (u >> 31 == 0) {
|
||||||
return 0.0; // Compiler requires return
|
return 0.0;
|
||||||
} else {
|
} else {
|
||||||
-1.0
|
return -1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,14 +71,14 @@ fn floor64(x: f64) -> f64 {
|
|||||||
if (e <= 0x3FF-1) {
|
if (e <= 0x3FF-1) {
|
||||||
math.forceEval(y);
|
math.forceEval(y);
|
||||||
if (u >> 63 != 0) {
|
if (u >> 63 != 0) {
|
||||||
return -1.0; // Compiler requires return.
|
return -1.0;
|
||||||
} else {
|
} else {
|
||||||
0.0
|
return 0.0;
|
||||||
}
|
}
|
||||||
} else if (y > 0) {
|
} else if (y > 0) {
|
||||||
x + y - 1
|
return x + y - 1;
|
||||||
} else {
|
} else {
|
||||||
x + y
|
return x + y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@ const math = @import("index.zig");
|
|||||||
const assert = @import("../debug.zig").assert;
|
const assert = @import("../debug.zig").assert;
|
||||||
|
|
||||||
pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {
|
pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(fma32, x, y, z),
|
f32 => @inlineCall(fma32, x, y, z),
|
||||||
f64 => @inlineCall(fma64, x, y ,z),
|
f64 => @inlineCall(fma64, x, y ,z),
|
||||||
else => @compileError("fma not implemented for " ++ @typeName(T)),
|
else => @compileError("fma not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fma32(x: f32, y: f32, z: f32) -> f32 {
|
fn fma32(x: f32, y: f32, z: f32) -> f32 {
|
||||||
@ -16,10 +16,10 @@ fn fma32(x: f32, y: f32, z: f32) -> f32 {
|
|||||||
const e = (u >> 52) & 0x7FF;
|
const e = (u >> 52) & 0x7FF;
|
||||||
|
|
||||||
if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or xy_z - xy == z) {
|
if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or xy_z - xy == z) {
|
||||||
f32(xy_z)
|
return f32(xy_z);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Handle inexact case with double-rounding
|
// TODO: Handle inexact case with double-rounding
|
||||||
f32(xy_z)
|
return f32(xy_z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,9 +64,9 @@ fn fma64(x: f64, y: f64, z: f64) -> f64 {
|
|||||||
|
|
||||||
const adj = add_adjusted(r.lo, xy.lo);
|
const adj = add_adjusted(r.lo, xy.lo);
|
||||||
if (spread + math.ilogb(r.hi) > -1023) {
|
if (spread + math.ilogb(r.hi) > -1023) {
|
||||||
math.scalbn(r.hi + adj, spread)
|
return math.scalbn(r.hi + adj, spread);
|
||||||
} else {
|
} else {
|
||||||
add_and_denorm(r.hi, adj, spread)
|
return add_and_denorm(r.hi, adj, spread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ fn dd_add(a: f64, b: f64) -> dd {
|
|||||||
ret.hi = a + b;
|
ret.hi = a + b;
|
||||||
const s = ret.hi - a;
|
const s = ret.hi - a;
|
||||||
ret.lo = (a - (ret.hi - s)) + (b - s);
|
ret.lo = (a - (ret.hi - s)) + (b - s);
|
||||||
ret
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dd_mul(a: f64, b: f64) -> dd {
|
fn dd_mul(a: f64, b: f64) -> dd {
|
||||||
@ -99,7 +99,7 @@ fn dd_mul(a: f64, b: f64) -> dd {
|
|||||||
|
|
||||||
ret.hi = p + q;
|
ret.hi = p + q;
|
||||||
ret.lo = p - ret.hi + q + la * lb;
|
ret.lo = p - ret.hi + q + la * lb;
|
||||||
ret
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_adjusted(a: f64, b: f64) -> f64 {
|
fn add_adjusted(a: f64, b: f64) -> f64 {
|
||||||
@ -113,7 +113,7 @@ fn add_adjusted(a: f64, b: f64) -> f64 {
|
|||||||
sum.hi = @bitCast(f64, uhii);
|
sum.hi = @bitCast(f64, uhii);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sum.hi
|
return sum.hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 {
|
fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 {
|
||||||
@ -127,7 +127,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 {
|
|||||||
sum.hi = @bitCast(f64, uhii);
|
sum.hi = @bitCast(f64, uhii);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
math.scalbn(sum.hi, scale)
|
return math.scalbn(sum.hi, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.fma" {
|
test "math.fma" {
|
||||||
|
@ -8,21 +8,21 @@ const math = @import("index.zig");
|
|||||||
const assert = @import("../debug.zig").assert;
|
const assert = @import("../debug.zig").assert;
|
||||||
|
|
||||||
fn frexp_result(comptime T: type) -> type {
|
fn frexp_result(comptime T: type) -> type {
|
||||||
struct {
|
return struct {
|
||||||
significand: T,
|
significand: T,
|
||||||
exponent: i32,
|
exponent: i32,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
pub const frexp32_result = frexp_result(f32);
|
pub const frexp32_result = frexp_result(f32);
|
||||||
pub const frexp64_result = frexp_result(f64);
|
pub const frexp64_result = frexp_result(f64);
|
||||||
|
|
||||||
pub fn frexp(x: var) -> frexp_result(@typeOf(x)) {
|
pub fn frexp(x: var) -> frexp_result(@typeOf(x)) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(frexp32, x),
|
f32 => @inlineCall(frexp32, x),
|
||||||
f64 => @inlineCall(frexp64, x),
|
f64 => @inlineCall(frexp64, x),
|
||||||
else => @compileError("frexp not implemented for " ++ @typeName(T)),
|
else => @compileError("frexp not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frexp32(x: f32) -> frexp32_result {
|
fn frexp32(x: f32) -> frexp32_result {
|
||||||
@ -59,7 +59,7 @@ fn frexp32(x: f32) -> frexp32_result {
|
|||||||
y &= 0x807FFFFF;
|
y &= 0x807FFFFF;
|
||||||
y |= 0x3F000000;
|
y |= 0x3F000000;
|
||||||
result.significand = @bitCast(f32, y);
|
result.significand = @bitCast(f32, y);
|
||||||
result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frexp64(x: f64) -> frexp64_result {
|
fn frexp64(x: f64) -> frexp64_result {
|
||||||
@ -96,7 +96,7 @@ fn frexp64(x: f64) -> frexp64_result {
|
|||||||
y &= 0x800FFFFFFFFFFFFF;
|
y &= 0x800FFFFFFFFFFFFF;
|
||||||
y |= 0x3FE0000000000000;
|
y |= 0x3FE0000000000000;
|
||||||
result.significand = @bitCast(f64, y);
|
result.significand = @bitCast(f64, y);
|
||||||
result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.frexp" {
|
test "math.frexp" {
|
||||||
|
@ -9,11 +9,11 @@ const math = @import("index.zig");
|
|||||||
const assert = @import("../debug.zig").assert;
|
const assert = @import("../debug.zig").assert;
|
||||||
|
|
||||||
pub fn hypot(comptime T: type, x: T, y: T) -> T {
|
pub fn hypot(comptime T: type, x: T, y: T) -> T {
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(hypot32, x, y),
|
f32 => @inlineCall(hypot32, x, y),
|
||||||
f64 => @inlineCall(hypot64, x, y),
|
f64 => @inlineCall(hypot64, x, y),
|
||||||
else => @compileError("hypot not implemented for " ++ @typeName(T)),
|
else => @compileError("hypot not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hypot32(x: f32, y: f32) -> f32 {
|
fn hypot32(x: f32, y: f32) -> f32 {
|
||||||
@ -48,7 +48,7 @@ fn hypot32(x: f32, y: f32) -> f32 {
|
|||||||
yy *= 0x1.0p-90;
|
yy *= 0x1.0p-90;
|
||||||
}
|
}
|
||||||
|
|
||||||
z * math.sqrt(f32(f64(x) * x + f64(y) * y))
|
return z * math.sqrt(f32(f64(x) * x + f64(y) * y));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sq(hi: &f64, lo: &f64, x: f64) {
|
fn sq(hi: &f64, lo: &f64, x: f64) {
|
||||||
@ -109,7 +109,7 @@ fn hypot64(x: f64, y: f64) -> f64 {
|
|||||||
sq(&hx, &lx, x);
|
sq(&hx, &lx, x);
|
||||||
sq(&hy, &ly, y);
|
sq(&hy, &ly, y);
|
||||||
|
|
||||||
z * math.sqrt(ly + lx + hy + hx)
|
return z * math.sqrt(ly + lx + hy + hx);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.hypot" {
|
test "math.hypot" {
|
||||||
|
@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn ilogb(x: var) -> i32 {
|
pub fn ilogb(x: var) -> i32 {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(ilogb32, x),
|
f32 => @inlineCall(ilogb32, x),
|
||||||
f64 => @inlineCall(ilogb64, x),
|
f64 => @inlineCall(ilogb64, x),
|
||||||
else => @compileError("ilogb not implemented for " ++ @typeName(T)),
|
else => @compileError("ilogb not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Should these be exposed publically?
|
// NOTE: Should these be exposed publically?
|
||||||
@ -53,7 +53,7 @@ fn ilogb32(x: f32) -> i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e - 0x7F
|
return e - 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ilogb64(x: f64) -> i32 {
|
fn ilogb64(x: f64) -> i32 {
|
||||||
@ -88,7 +88,7 @@ fn ilogb64(x: f64) -> i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e - 0x3FF
|
return e - 0x3FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.ilogb" {
|
test "math.ilogb" {
|
||||||
|
@ -36,7 +36,7 @@ pub const inf = @import("inf.zig").inf;
|
|||||||
|
|
||||||
pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) -> bool {
|
pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) -> bool {
|
||||||
assert(@typeId(T) == TypeId.Float);
|
assert(@typeId(T) == TypeId.Float);
|
||||||
fabs(x - y) < epsilon
|
return fabs(x - y) < epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Hide the following in an internal module.
|
// TODO: Hide the following in an internal module.
|
||||||
@ -175,7 +175,7 @@ test "math" {
|
|||||||
|
|
||||||
|
|
||||||
pub fn min(x: var, y: var) -> @typeOf(x + y) {
|
pub fn min(x: var, y: var) -> @typeOf(x + y) {
|
||||||
if (x < y) x else y
|
return if (x < y) x else y;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.min" {
|
test "math.min" {
|
||||||
@ -183,7 +183,7 @@ test "math.min" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn max(x: var, y: var) -> @typeOf(x + y) {
|
pub fn max(x: var, y: var) -> @typeOf(x + y) {
|
||||||
if (x > y) x else y
|
return if (x > y) x else y;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.max" {
|
test "math.max" {
|
||||||
@ -193,19 +193,19 @@ test "math.max" {
|
|||||||
error Overflow;
|
error Overflow;
|
||||||
pub fn mul(comptime T: type, a: T, b: T) -> %T {
|
pub fn mul(comptime T: type, a: T, b: T) -> %T {
|
||||||
var answer: T = undefined;
|
var answer: T = undefined;
|
||||||
if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer
|
return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
error Overflow;
|
error Overflow;
|
||||||
pub fn add(comptime T: type, a: T, b: T) -> %T {
|
pub fn add(comptime T: type, a: T, b: T) -> %T {
|
||||||
var answer: T = undefined;
|
var answer: T = undefined;
|
||||||
if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer
|
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
error Overflow;
|
error Overflow;
|
||||||
pub fn sub(comptime T: type, a: T, b: T) -> %T {
|
pub fn sub(comptime T: type, a: T, b: T) -> %T {
|
||||||
var answer: T = undefined;
|
var answer: T = undefined;
|
||||||
if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer
|
return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn negate(x: var) -> %@typeOf(x) {
|
pub fn negate(x: var) -> %@typeOf(x) {
|
||||||
@ -215,7 +215,7 @@ pub fn negate(x: var) -> %@typeOf(x) {
|
|||||||
error Overflow;
|
error Overflow;
|
||||||
pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) -> %T {
|
pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) -> %T {
|
||||||
var answer: T = undefined;
|
var answer: T = undefined;
|
||||||
if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer
|
return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shifts left. Overflowed bits are truncated.
|
/// Shifts left. Overflowed bits are truncated.
|
||||||
@ -267,7 +267,7 @@ test "math.shr" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn Log2Int(comptime T: type) -> type {
|
pub fn Log2Int(comptime T: type) -> type {
|
||||||
@IntType(false, log2(T.bit_count))
|
return @IntType(false, log2(T.bit_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math overflow functions" {
|
test "math overflow functions" {
|
||||||
|
@ -2,9 +2,9 @@ const math = @import("index.zig");
|
|||||||
const assert = @import("../debug.zig").assert;
|
const assert = @import("../debug.zig").assert;
|
||||||
|
|
||||||
pub fn inf(comptime T: type) -> T {
|
pub fn inf(comptime T: type) -> T {
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @bitCast(f32, math.inf_u32),
|
f32 => @bitCast(f32, math.inf_u32),
|
||||||
f64 => @bitCast(f64, math.inf_u64),
|
f64 => @bitCast(f64, math.inf_u64),
|
||||||
else => @compileError("inf not implemented for " ++ @typeName(T)),
|
else => @compileError("inf not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,11 @@ pub fn isFinite(x: var) -> bool {
|
|||||||
switch (T) {
|
switch (T) {
|
||||||
f32 => {
|
f32 => {
|
||||||
const bits = @bitCast(u32, x);
|
const bits = @bitCast(u32, x);
|
||||||
bits & 0x7FFFFFFF < 0x7F800000
|
return bits & 0x7FFFFFFF < 0x7F800000;
|
||||||
},
|
},
|
||||||
f64 => {
|
f64 => {
|
||||||
const bits = @bitCast(u64, x);
|
const bits = @bitCast(u64, x);
|
||||||
bits & (@maxValue(u64) >> 1) < (0x7FF << 52)
|
return bits & (@maxValue(u64) >> 1) < (0x7FF << 52);
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
@compileError("isFinite not implemented for " ++ @typeName(T));
|
@compileError("isFinite not implemented for " ++ @typeName(T));
|
||||||
|
@ -6,11 +6,11 @@ pub fn isInf(x: var) -> bool {
|
|||||||
switch (T) {
|
switch (T) {
|
||||||
f32 => {
|
f32 => {
|
||||||
const bits = @bitCast(u32, x);
|
const bits = @bitCast(u32, x);
|
||||||
bits & 0x7FFFFFFF == 0x7F800000
|
return bits & 0x7FFFFFFF == 0x7F800000;
|
||||||
},
|
},
|
||||||
f64 => {
|
f64 => {
|
||||||
const bits = @bitCast(u64, x);
|
const bits = @bitCast(u64, x);
|
||||||
bits & (@maxValue(u64) >> 1) == (0x7FF << 52)
|
return bits & (@maxValue(u64) >> 1) == (0x7FF << 52);
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
@compileError("isInf not implemented for " ++ @typeName(T));
|
@compileError("isInf not implemented for " ++ @typeName(T));
|
||||||
@ -22,10 +22,10 @@ pub fn isPositiveInf(x: var) -> bool {
|
|||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
switch (T) {
|
||||||
f32 => {
|
f32 => {
|
||||||
@bitCast(u32, x) == 0x7F800000
|
return @bitCast(u32, x) == 0x7F800000;
|
||||||
},
|
},
|
||||||
f64 => {
|
f64 => {
|
||||||
@bitCast(u64, x) == 0x7FF << 52
|
return @bitCast(u64, x) == 0x7FF << 52;
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
@compileError("isPositiveInf not implemented for " ++ @typeName(T));
|
@compileError("isPositiveInf not implemented for " ++ @typeName(T));
|
||||||
@ -37,10 +37,10 @@ pub fn isNegativeInf(x: var) -> bool {
|
|||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
switch (T) {
|
||||||
f32 => {
|
f32 => {
|
||||||
@bitCast(u32, x) == 0xFF800000
|
return @bitCast(u32, x) == 0xFF800000;
|
||||||
},
|
},
|
||||||
f64 => {
|
f64 => {
|
||||||
@bitCast(u64, x) == 0xFFF << 52
|
return @bitCast(u64, x) == 0xFFF << 52;
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
@compileError("isNegativeInf not implemented for " ++ @typeName(T));
|
@compileError("isNegativeInf not implemented for " ++ @typeName(T));
|
||||||
|
@ -6,11 +6,11 @@ pub fn isNan(x: var) -> bool {
|
|||||||
switch (T) {
|
switch (T) {
|
||||||
f32 => {
|
f32 => {
|
||||||
const bits = @bitCast(u32, x);
|
const bits = @bitCast(u32, x);
|
||||||
bits & 0x7FFFFFFF > 0x7F800000
|
return bits & 0x7FFFFFFF > 0x7F800000;
|
||||||
},
|
},
|
||||||
f64 => {
|
f64 => {
|
||||||
const bits = @bitCast(u64, x);
|
const bits = @bitCast(u64, x);
|
||||||
(bits & (@maxValue(u64) >> 1)) > (u64(0x7FF) << 52)
|
return (bits & (@maxValue(u64) >> 1)) > (u64(0x7FF) << 52);
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
@compileError("isNan not implemented for " ++ @typeName(T));
|
@compileError("isNan not implemented for " ++ @typeName(T));
|
||||||
@ -21,7 +21,7 @@ pub fn isNan(x: var) -> bool {
|
|||||||
// Note: A signalling nan is identical to a standard right now by may have a different bit
|
// Note: A signalling nan is identical to a standard right now by may have a different bit
|
||||||
// representation in the future when required.
|
// representation in the future when required.
|
||||||
pub fn isSignalNan(x: var) -> bool {
|
pub fn isSignalNan(x: var) -> bool {
|
||||||
isNan(x)
|
return isNan(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.isNan" {
|
test "math.isNan" {
|
||||||
|
@ -6,11 +6,11 @@ pub fn isNormal(x: var) -> bool {
|
|||||||
switch (T) {
|
switch (T) {
|
||||||
f32 => {
|
f32 => {
|
||||||
const bits = @bitCast(u32, x);
|
const bits = @bitCast(u32, x);
|
||||||
(bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000
|
return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000;
|
||||||
},
|
},
|
||||||
f64 => {
|
f64 => {
|
||||||
const bits = @bitCast(u64, x);
|
const bits = @bitCast(u64, x);
|
||||||
(bits + (1 << 52)) & (@maxValue(u64) >> 1) >= (1 << 53)
|
return (bits + (1 << 52)) & (@maxValue(u64) >> 1) >= (1 << 53);
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
@compileError("isNormal not implemented for " ++ @typeName(T));
|
@compileError("isNormal not implemented for " ++ @typeName(T));
|
||||||
|
@ -14,7 +14,7 @@ pub fn ln(x: var) -> @typeOf(x) {
|
|||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (@typeId(T)) {
|
switch (@typeId(T)) {
|
||||||
TypeId.FloatLiteral => {
|
TypeId.FloatLiteral => {
|
||||||
return @typeOf(1.0)(ln_64(x))
|
return @typeOf(1.0)(ln_64(x));
|
||||||
},
|
},
|
||||||
TypeId.Float => {
|
TypeId.Float => {
|
||||||
return switch (T) {
|
return switch (T) {
|
||||||
@ -84,7 +84,7 @@ pub fn ln_32(x_: f32) -> f32 {
|
|||||||
const hfsq = 0.5 * f * f;
|
const hfsq = 0.5 * f * f;
|
||||||
const dk = f32(k);
|
const dk = f32(k);
|
||||||
|
|
||||||
s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi
|
return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ln_64(x_: f64) -> f64 {
|
pub fn ln_64(x_: f64) -> f64 {
|
||||||
@ -116,7 +116,7 @@ pub fn ln_64(x_: f64) -> f64 {
|
|||||||
// subnormal, scale x
|
// subnormal, scale x
|
||||||
k -= 54;
|
k -= 54;
|
||||||
x *= 0x1.0p54;
|
x *= 0x1.0p54;
|
||||||
hx = u32(@bitCast(u64, ix) >> 32)
|
hx = u32(@bitCast(u64, ix) >> 32);
|
||||||
}
|
}
|
||||||
else if (hx >= 0x7FF00000) {
|
else if (hx >= 0x7FF00000) {
|
||||||
return x;
|
return x;
|
||||||
@ -142,7 +142,7 @@ pub fn ln_64(x_: f64) -> f64 {
|
|||||||
const R = t2 + t1;
|
const R = t2 + t1;
|
||||||
const dk = f64(k);
|
const dk = f64(k);
|
||||||
|
|
||||||
s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi
|
return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.ln" {
|
test "math.ln" {
|
||||||
|
@ -29,7 +29,7 @@ pub fn log(comptime T: type, base: T, x: T) -> T {
|
|||||||
f32 => return f32(math.ln(f64(x)) / math.ln(f64(base))),
|
f32 => return f32(math.ln(f64(x)) / math.ln(f64(base))),
|
||||||
f64 => return math.ln(x) / math.ln(f64(base)),
|
f64 => return math.ln(x) / math.ln(f64(base)),
|
||||||
else => @compileError("log not implemented for " ++ @typeName(T)),
|
else => @compileError("log not implemented for " ++ @typeName(T)),
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
else => {
|
else => {
|
||||||
|
@ -14,7 +14,7 @@ pub fn log10(x: var) -> @typeOf(x) {
|
|||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (@typeId(T)) {
|
switch (@typeId(T)) {
|
||||||
TypeId.FloatLiteral => {
|
TypeId.FloatLiteral => {
|
||||||
return @typeOf(1.0)(log10_64(x))
|
return @typeOf(1.0)(log10_64(x));
|
||||||
},
|
},
|
||||||
TypeId.Float => {
|
TypeId.Float => {
|
||||||
return switch (T) {
|
return switch (T) {
|
||||||
@ -90,7 +90,7 @@ pub fn log10_32(x_: f32) -> f32 {
|
|||||||
const lo = f - hi - hfsq + s * (hfsq + R);
|
const lo = f - hi - hfsq + s * (hfsq + R);
|
||||||
const dk = f32(k);
|
const dk = f32(k);
|
||||||
|
|
||||||
dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi
|
return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log10_64(x_: f64) -> f64 {
|
pub fn log10_64(x_: f64) -> f64 {
|
||||||
@ -124,7 +124,7 @@ pub fn log10_64(x_: f64) -> f64 {
|
|||||||
// subnormal, scale x
|
// subnormal, scale x
|
||||||
k -= 54;
|
k -= 54;
|
||||||
x *= 0x1.0p54;
|
x *= 0x1.0p54;
|
||||||
hx = u32(@bitCast(u64, x) >> 32)
|
hx = u32(@bitCast(u64, x) >> 32);
|
||||||
}
|
}
|
||||||
else if (hx >= 0x7FF00000) {
|
else if (hx >= 0x7FF00000) {
|
||||||
return x;
|
return x;
|
||||||
@ -167,7 +167,7 @@ pub fn log10_64(x_: f64) -> f64 {
|
|||||||
val_lo += (y - ww) + val_hi;
|
val_lo += (y - ww) + val_hi;
|
||||||
val_hi = ww;
|
val_hi = ww;
|
||||||
|
|
||||||
val_lo + val_hi
|
return val_lo + val_hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.log10" {
|
test "math.log10" {
|
||||||
|
@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn log1p(x: var) -> @typeOf(x) {
|
pub fn log1p(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(log1p_32, x),
|
f32 => @inlineCall(log1p_32, x),
|
||||||
f64 => @inlineCall(log1p_64, x),
|
f64 => @inlineCall(log1p_64, x),
|
||||||
else => @compileError("log1p not implemented for " ++ @typeName(T)),
|
else => @compileError("log1p not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log1p_32(x: f32) -> f32 {
|
fn log1p_32(x: f32) -> f32 {
|
||||||
@ -91,7 +91,7 @@ fn log1p_32(x: f32) -> f32 {
|
|||||||
const hfsq = 0.5 * f * f;
|
const hfsq = 0.5 * f * f;
|
||||||
const dk = f32(k);
|
const dk = f32(k);
|
||||||
|
|
||||||
s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
|
return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log1p_64(x: f64) -> f64 {
|
fn log1p_64(x: f64) -> f64 {
|
||||||
@ -172,7 +172,7 @@ fn log1p_64(x: f64) -> f64 {
|
|||||||
const R = t2 + t1;
|
const R = t2 + t1;
|
||||||
const dk = f64(k);
|
const dk = f64(k);
|
||||||
|
|
||||||
s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
|
return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.log1p" {
|
test "math.log1p" {
|
||||||
|
@ -14,7 +14,7 @@ pub fn log2(x: var) -> @typeOf(x) {
|
|||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (@typeId(T)) {
|
switch (@typeId(T)) {
|
||||||
TypeId.FloatLiteral => {
|
TypeId.FloatLiteral => {
|
||||||
return @typeOf(1.0)(log2_64(x))
|
return @typeOf(1.0)(log2_64(x));
|
||||||
},
|
},
|
||||||
TypeId.Float => {
|
TypeId.Float => {
|
||||||
return switch (T) {
|
return switch (T) {
|
||||||
@ -26,7 +26,7 @@ pub fn log2(x: var) -> @typeOf(x) {
|
|||||||
TypeId.IntLiteral => comptime {
|
TypeId.IntLiteral => comptime {
|
||||||
var result = 0;
|
var result = 0;
|
||||||
var x_shifted = x;
|
var x_shifted = x;
|
||||||
while ({x_shifted >>= 1; x_shifted != 0}) : (result += 1) {}
|
while (b: {x_shifted >>= 1; break :b x_shifted != 0;}) : (result += 1) {}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
TypeId.Int => {
|
TypeId.Int => {
|
||||||
@ -94,7 +94,7 @@ pub fn log2_32(x_: f32) -> f32 {
|
|||||||
u &= 0xFFFFF000;
|
u &= 0xFFFFF000;
|
||||||
hi = @bitCast(f32, u);
|
hi = @bitCast(f32, u);
|
||||||
const lo = f - hi - hfsq + s * (hfsq + R);
|
const lo = f - hi - hfsq + s * (hfsq + R);
|
||||||
(lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k)
|
return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log2_64(x_: f64) -> f64 {
|
pub fn log2_64(x_: f64) -> f64 {
|
||||||
@ -165,7 +165,7 @@ pub fn log2_64(x_: f64) -> f64 {
|
|||||||
val_lo += (y - ww) + val_hi;
|
val_lo += (y - ww) + val_hi;
|
||||||
val_hi = ww;
|
val_hi = ww;
|
||||||
|
|
||||||
val_lo + val_hi
|
return val_lo + val_hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.log2" {
|
test "math.log2" {
|
||||||
|
@ -7,21 +7,21 @@ const math = @import("index.zig");
|
|||||||
const assert = @import("../debug.zig").assert;
|
const assert = @import("../debug.zig").assert;
|
||||||
|
|
||||||
fn modf_result(comptime T: type) -> type {
|
fn modf_result(comptime T: type) -> type {
|
||||||
struct {
|
return struct {
|
||||||
fpart: T,
|
fpart: T,
|
||||||
ipart: T,
|
ipart: T,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
pub const modf32_result = modf_result(f32);
|
pub const modf32_result = modf_result(f32);
|
||||||
pub const modf64_result = modf_result(f64);
|
pub const modf64_result = modf_result(f64);
|
||||||
|
|
||||||
pub fn modf(x: var) -> modf_result(@typeOf(x)) {
|
pub fn modf(x: var) -> modf_result(@typeOf(x)) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(modf32, x),
|
f32 => @inlineCall(modf32, x),
|
||||||
f64 => @inlineCall(modf64, x),
|
f64 => @inlineCall(modf64, x),
|
||||||
else => @compileError("modf not implemented for " ++ @typeName(T)),
|
else => @compileError("modf not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modf32(x: f32) -> modf32_result {
|
fn modf32(x: f32) -> modf32_result {
|
||||||
@ -66,7 +66,7 @@ fn modf32(x: f32) -> modf32_result {
|
|||||||
const uf = @bitCast(f32, u & ~mask);
|
const uf = @bitCast(f32, u & ~mask);
|
||||||
result.ipart = uf;
|
result.ipart = uf;
|
||||||
result.fpart = x - uf;
|
result.fpart = x - uf;
|
||||||
result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modf64(x: f64) -> modf64_result {
|
fn modf64(x: f64) -> modf64_result {
|
||||||
@ -110,7 +110,7 @@ fn modf64(x: f64) -> modf64_result {
|
|||||||
const uf = @bitCast(f64, u & ~mask);
|
const uf = @bitCast(f64, u & ~mask);
|
||||||
result.ipart = uf;
|
result.ipart = uf;
|
||||||
result.fpart = x - uf;
|
result.fpart = x - uf;
|
||||||
result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.modf" {
|
test "math.modf" {
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
const math = @import("index.zig");
|
const math = @import("index.zig");
|
||||||
|
|
||||||
pub fn nan(comptime T: type) -> T {
|
pub fn nan(comptime T: type) -> T {
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @bitCast(f32, math.nan_u32),
|
f32 => @bitCast(f32, math.nan_u32),
|
||||||
f64 => @bitCast(f64, math.nan_u64),
|
f64 => @bitCast(f64, math.nan_u64),
|
||||||
else => @compileError("nan not implemented for " ++ @typeName(T)),
|
else => @compileError("nan not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: A signalling nan is identical to a standard right now by may have a different bit
|
// Note: A signalling nan is identical to a standard right now by may have a different bit
|
||||||
// representation in the future when required.
|
// representation in the future when required.
|
||||||
pub fn snan(comptime T: type) -> T {
|
pub fn snan(comptime T: type) -> T {
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @bitCast(f32, math.nan_u32),
|
f32 => @bitCast(f32, math.nan_u32),
|
||||||
f64 => @bitCast(f64, math.nan_u64),
|
f64 => @bitCast(f64, math.nan_u64),
|
||||||
else => @compileError("snan not implemented for " ++ @typeName(T)),
|
else => @compileError("snan not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
@ -166,12 +166,12 @@ pub fn pow(comptime T: type, x: T, y: T) -> T {
|
|||||||
ae = -ae;
|
ae = -ae;
|
||||||
}
|
}
|
||||||
|
|
||||||
math.scalbn(a1, ae)
|
return math.scalbn(a1, ae);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isOddInteger(x: f64) -> bool {
|
fn isOddInteger(x: f64) -> bool {
|
||||||
const r = math.modf(x);
|
const r = math.modf(x);
|
||||||
r.fpart == 0.0 and i64(r.ipart) & 1 == 1
|
return r.fpart == 0.0 and i64(r.ipart) & 1 == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.pow" {
|
test "math.pow" {
|
||||||
|
@ -10,11 +10,11 @@ const math = @import("index.zig");
|
|||||||
|
|
||||||
pub fn round(x: var) -> @typeOf(x) {
|
pub fn round(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(round32, x),
|
f32 => @inlineCall(round32, x),
|
||||||
f64 => @inlineCall(round64, x),
|
f64 => @inlineCall(round64, x),
|
||||||
else => @compileError("round not implemented for " ++ @typeName(T)),
|
else => @compileError("round not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn round32(x_: f32) -> f32 {
|
fn round32(x_: f32) -> f32 {
|
||||||
@ -48,9 +48,9 @@ fn round32(x_: f32) -> f32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (u >> 31 != 0) {
|
if (u >> 31 != 0) {
|
||||||
-y
|
return -y;
|
||||||
} else {
|
} else {
|
||||||
y
|
return y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,9 +85,9 @@ fn round64(x_: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (u >> 63 != 0) {
|
if (u >> 63 != 0) {
|
||||||
-y
|
return -y;
|
||||||
} else {
|
} else {
|
||||||
y
|
return y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn scalbn(x: var, n: i32) -> @typeOf(x) {
|
pub fn scalbn(x: var, n: i32) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(scalbn32, x, n),
|
f32 => @inlineCall(scalbn32, x, n),
|
||||||
f64 => @inlineCall(scalbn64, x, n),
|
f64 => @inlineCall(scalbn64, x, n),
|
||||||
else => @compileError("scalbn not implemented for " ++ @typeName(T)),
|
else => @compileError("scalbn not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scalbn32(x: f32, n_: i32) -> f32 {
|
fn scalbn32(x: f32, n_: i32) -> f32 {
|
||||||
@ -37,7 +37,7 @@ fn scalbn32(x: f32, n_: i32) -> f32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const u = u32(n +% 0x7F) << 23;
|
const u = u32(n +% 0x7F) << 23;
|
||||||
y * @bitCast(f32, u)
|
return y * @bitCast(f32, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scalbn64(x: f64, n_: i32) -> f64 {
|
fn scalbn64(x: f64, n_: i32) -> f64 {
|
||||||
@ -67,7 +67,7 @@ fn scalbn64(x: f64, n_: i32) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const u = u64(n +% 0x3FF) << 52;
|
const u = u64(n +% 0x3FF) << 52;
|
||||||
y * @bitCast(f64, u)
|
return y * @bitCast(f64, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.scalbn" {
|
test "math.scalbn" {
|
||||||
|
@ -3,21 +3,21 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn signbit(x: var) -> bool {
|
pub fn signbit(x: var) -> bool {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(signbit32, x),
|
f32 => @inlineCall(signbit32, x),
|
||||||
f64 => @inlineCall(signbit64, x),
|
f64 => @inlineCall(signbit64, x),
|
||||||
else => @compileError("signbit not implemented for " ++ @typeName(T)),
|
else => @compileError("signbit not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signbit32(x: f32) -> bool {
|
fn signbit32(x: f32) -> bool {
|
||||||
const bits = @bitCast(u32, x);
|
const bits = @bitCast(u32, x);
|
||||||
bits >> 31 != 0
|
return bits >> 31 != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signbit64(x: f64) -> bool {
|
fn signbit64(x: f64) -> bool {
|
||||||
const bits = @bitCast(u64, x);
|
const bits = @bitCast(u64, x);
|
||||||
bits >> 63 != 0
|
return bits >> 63 != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.signbit" {
|
test "math.signbit" {
|
||||||
|
@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn sin(x: var) -> @typeOf(x) {
|
pub fn sin(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(sin32, x),
|
f32 => @inlineCall(sin32, x),
|
||||||
f64 => @inlineCall(sin64, x),
|
f64 => @inlineCall(sin64, x),
|
||||||
else => @compileError("sin not implemented for " ++ @typeName(T)),
|
else => @compileError("sin not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// sin polynomial coefficients
|
// sin polynomial coefficients
|
||||||
@ -75,18 +75,18 @@ fn sin32(x_: f32) -> f32 {
|
|||||||
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
||||||
const w = z * z;
|
const w = z * z;
|
||||||
|
|
||||||
const r = {
|
const r = r: {
|
||||||
if (j == 1 or j == 2) {
|
if (j == 1 or j == 2) {
|
||||||
1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))))
|
break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
|
||||||
} else {
|
} else {
|
||||||
z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))))
|
break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sign) {
|
if (sign) {
|
||||||
-r
|
return -r;
|
||||||
} else {
|
} else {
|
||||||
r
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,25 +127,25 @@ fn sin64(x_: f64) -> f64 {
|
|||||||
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
||||||
const w = z * z;
|
const w = z * z;
|
||||||
|
|
||||||
const r = {
|
const r = r: {
|
||||||
if (j == 1 or j == 2) {
|
if (j == 1 or j == 2) {
|
||||||
1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))))
|
break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
|
||||||
} else {
|
} else {
|
||||||
z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))))
|
break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sign) {
|
if (sign) {
|
||||||
-r
|
return -r;
|
||||||
} else {
|
} else {
|
||||||
r
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.sin" {
|
test "math.sin" {
|
||||||
assert(sin(f32(0.0)) == sin32(0.0));
|
assert(sin(f32(0.0)) == sin32(0.0));
|
||||||
assert(sin(f64(0.0)) == sin64(0.0));
|
assert(sin(f64(0.0)) == sin64(0.0));
|
||||||
assert(comptime {math.sin(f64(2))} == math.sin(f64(2)));
|
assert(comptime (math.sin(f64(2))) == math.sin(f64(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.sin32" {
|
test "math.sin32" {
|
||||||
|
@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2;
|
|||||||
|
|
||||||
pub fn sinh(x: var) -> @typeOf(x) {
|
pub fn sinh(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(sinh32, x),
|
f32 => @inlineCall(sinh32, x),
|
||||||
f64 => @inlineCall(sinh64, x),
|
f64 => @inlineCall(sinh64, x),
|
||||||
else => @compileError("sinh not implemented for " ++ @typeName(T)),
|
else => @compileError("sinh not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// sinh(x) = (exp(x) - 1 / exp(x)) / 2
|
// sinh(x) = (exp(x) - 1 / exp(x)) / 2
|
||||||
@ -49,7 +49,7 @@ fn sinh32(x: f32) -> f32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// |x| > log(FLT_MAX) or nan
|
// |x| > log(FLT_MAX) or nan
|
||||||
2 * h * expo2(ax)
|
return 2 * h * expo2(ax);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sinh64(x: f64) -> f64 {
|
fn sinh64(x: f64) -> f64 {
|
||||||
@ -83,7 +83,7 @@ fn sinh64(x: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// |x| > log(DBL_MAX) or nan
|
// |x| > log(DBL_MAX) or nan
|
||||||
2 * h * expo2(ax)
|
return 2 * h * expo2(ax);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.sinh" {
|
test "math.sinh" {
|
||||||
|
@ -14,7 +14,7 @@ pub fn sqrt(x: var) -> (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @
|
|||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (@typeId(T)) {
|
switch (@typeId(T)) {
|
||||||
TypeId.FloatLiteral => {
|
TypeId.FloatLiteral => {
|
||||||
return T(sqrt64(x))
|
return T(sqrt64(x));
|
||||||
},
|
},
|
||||||
TypeId.Float => {
|
TypeId.Float => {
|
||||||
return switch (T) {
|
return switch (T) {
|
||||||
@ -64,7 +64,7 @@ fn sqrt32(x: f32) -> f32 {
|
|||||||
// subnormal
|
// subnormal
|
||||||
var i: i32 = 0;
|
var i: i32 = 0;
|
||||||
while (ix & 0x00800000 == 0) : (i += 1) {
|
while (ix & 0x00800000 == 0) : (i += 1) {
|
||||||
ix <<= 1
|
ix <<= 1;
|
||||||
}
|
}
|
||||||
m -= i - 1;
|
m -= i - 1;
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@ fn sqrt32(x: f32) -> f32 {
|
|||||||
|
|
||||||
ix = (q >> 1) + 0x3f000000;
|
ix = (q >> 1) + 0x3f000000;
|
||||||
ix += m << 23;
|
ix += m << 23;
|
||||||
@bitCast(f32, ix)
|
return @bitCast(f32, ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
|
// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
|
||||||
@ -153,7 +153,7 @@ fn sqrt64(x: f64) -> f64 {
|
|||||||
// subnormal
|
// subnormal
|
||||||
var i: u32 = 0;
|
var i: u32 = 0;
|
||||||
while (ix0 & 0x00100000 == 0) : (i += 1) {
|
while (ix0 & 0x00100000 == 0) : (i += 1) {
|
||||||
ix0 <<= 1
|
ix0 <<= 1;
|
||||||
}
|
}
|
||||||
m -= i32(i) - 1;
|
m -= i32(i) - 1;
|
||||||
ix0 |= ix1 >> u5(32 - i);
|
ix0 |= ix1 >> u5(32 - i);
|
||||||
@ -245,7 +245,7 @@ fn sqrt64(x: f64) -> f64 {
|
|||||||
iix0 = iix0 +% (m << 20);
|
iix0 = iix0 +% (m << 20);
|
||||||
|
|
||||||
const uz = (u64(iix0) << 32) | ix1;
|
const uz = (u64(iix0) << 32) | ix1;
|
||||||
@bitCast(f64, uz)
|
return @bitCast(f64, uz);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.sqrt" {
|
test "math.sqrt" {
|
||||||
|
@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn tan(x: var) -> @typeOf(x) {
|
pub fn tan(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(tan32, x),
|
f32 => @inlineCall(tan32, x),
|
||||||
f64 => @inlineCall(tan64, x),
|
f64 => @inlineCall(tan64, x),
|
||||||
else => @compileError("tan not implemented for " ++ @typeName(T)),
|
else => @compileError("tan not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tp0 = -1.30936939181383777646E4;
|
const Tp0 = -1.30936939181383777646E4;
|
||||||
@ -62,11 +62,11 @@ fn tan32(x_: f32) -> f32 {
|
|||||||
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
||||||
const w = z * z;
|
const w = z * z;
|
||||||
|
|
||||||
var r = {
|
var r = r: {
|
||||||
if (w > 1e-14) {
|
if (w > 1e-14) {
|
||||||
z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4))
|
break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4));
|
||||||
} else {
|
} else {
|
||||||
z
|
break :r z;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ fn tan32(x_: f32) -> f32 {
|
|||||||
r = -r;
|
r = -r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tan64(x_: f64) -> f64 {
|
fn tan64(x_: f64) -> f64 {
|
||||||
@ -111,11 +111,11 @@ fn tan64(x_: f64) -> f64 {
|
|||||||
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
||||||
const w = z * z;
|
const w = z * z;
|
||||||
|
|
||||||
var r = {
|
var r = r: {
|
||||||
if (w > 1e-14) {
|
if (w > 1e-14) {
|
||||||
z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4))
|
break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4));
|
||||||
} else {
|
} else {
|
||||||
z
|
break :r z;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ fn tan64(x_: f64) -> f64 {
|
|||||||
r = -r;
|
r = -r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.tan" {
|
test "math.tan" {
|
||||||
|
@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2;
|
|||||||
|
|
||||||
pub fn tanh(x: var) -> @typeOf(x) {
|
pub fn tanh(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(tanh32, x),
|
f32 => @inlineCall(tanh32, x),
|
||||||
f64 => @inlineCall(tanh64, x),
|
f64 => @inlineCall(tanh64, x),
|
||||||
else => @compileError("tanh not implemented for " ++ @typeName(T)),
|
else => @compileError("tanh not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
|
// tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
|
||||||
@ -59,9 +59,9 @@ fn tanh32(x: f32) -> f32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (u >> 31 != 0) {
|
if (u >> 31 != 0) {
|
||||||
-t
|
return -t;
|
||||||
} else {
|
} else {
|
||||||
t
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,9 +104,9 @@ fn tanh64(x: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (u >> 63 != 0) {
|
if (u >> 63 != 0) {
|
||||||
-t
|
return -t;
|
||||||
} else {
|
} else {
|
||||||
t
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
|
|||||||
|
|
||||||
pub fn trunc(x: var) -> @typeOf(x) {
|
pub fn trunc(x: var) -> @typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
switch (T) {
|
return switch (T) {
|
||||||
f32 => @inlineCall(trunc32, x),
|
f32 => @inlineCall(trunc32, x),
|
||||||
f64 => @inlineCall(trunc64, x),
|
f64 => @inlineCall(trunc64, x),
|
||||||
else => @compileError("trunc not implemented for " ++ @typeName(T)),
|
else => @compileError("trunc not implemented for " ++ @typeName(T)),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trunc32(x: f32) -> f32 {
|
fn trunc32(x: f32) -> f32 {
|
||||||
@ -30,10 +30,10 @@ fn trunc32(x: f32) -> f32 {
|
|||||||
|
|
||||||
m = u32(@maxValue(u32)) >> u5(e);
|
m = u32(@maxValue(u32)) >> u5(e);
|
||||||
if (u & m == 0) {
|
if (u & m == 0) {
|
||||||
x
|
return x;
|
||||||
} else {
|
} else {
|
||||||
math.forceEval(x + 0x1p120);
|
math.forceEval(x + 0x1p120);
|
||||||
@bitCast(f32, u & ~m)
|
return @bitCast(f32, u & ~m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +51,10 @@ fn trunc64(x: f64) -> f64 {
|
|||||||
|
|
||||||
m = u64(@maxValue(u64)) >> u6(e);
|
m = u64(@maxValue(u64)) >> u6(e);
|
||||||
if (u & m == 0) {
|
if (u & m == 0) {
|
||||||
x
|
return x;
|
||||||
} else {
|
} else {
|
||||||
math.forceEval(x + 0x1p120);
|
math.forceEval(x + 0x1p120);
|
||||||
@bitCast(f64, u & ~m)
|
return @bitCast(f64, u & ~m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,11 +354,11 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) -> bool {
|
|||||||
/// split(" abc def ghi ", " ")
|
/// split(" abc def ghi ", " ")
|
||||||
/// Will return slices for "abc", "def", "ghi", null, in that order.
|
/// Will return slices for "abc", "def", "ghi", null, in that order.
|
||||||
pub fn split(buffer: []const u8, split_bytes: []const u8) -> SplitIterator {
|
pub fn split(buffer: []const u8, split_bytes: []const u8) -> SplitIterator {
|
||||||
SplitIterator {
|
return SplitIterator {
|
||||||
.index = 0,
|
.index = 0,
|
||||||
.buffer = buffer,
|
.buffer = buffer,
|
||||||
.split_bytes = split_bytes,
|
.split_bytes = split_bytes,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "mem.split" {
|
test "mem.split" {
|
||||||
@ -552,7 +552,7 @@ test "std.mem.reverse" {
|
|||||||
var arr = []i32{ 5, 3, 1, 2, 4 };
|
var arr = []i32{ 5, 3, 1, 2, 4 };
|
||||||
reverse(i32, arr[0..]);
|
reverse(i32, arr[0..]);
|
||||||
|
|
||||||
assert(eql(i32, arr, []i32{ 4, 2, 1, 3, 5 }))
|
assert(eql(i32, arr, []i32{ 4, 2, 1, 3, 5 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)
|
/// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)
|
||||||
@ -567,5 +567,5 @@ test "std.mem.rotate" {
|
|||||||
var arr = []i32{ 5, 3, 1, 2, 4 };
|
var arr = []i32{ 5, 3, 1, 2, 4 };
|
||||||
rotate(i32, arr[0..], 2);
|
rotate(i32, arr[0..], 2);
|
||||||
|
|
||||||
assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }))
|
assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));
|
||||||
}
|
}
|
||||||
|
22
std/net.zig
22
std/net.zig
@ -72,7 +72,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
|
|||||||
// if (family != AF_INET)
|
// if (family != AF_INET)
|
||||||
// buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
|
// buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
|
||||||
//
|
//
|
||||||
unreachable // TODO
|
unreachable; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@ -84,7 +84,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
|
|||||||
// else => {},
|
// else => {},
|
||||||
//};
|
//};
|
||||||
|
|
||||||
unreachable // TODO
|
unreachable; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
|
pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
|
||||||
@ -96,23 +96,23 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
|
|||||||
}
|
}
|
||||||
const socket_fd = i32(socket_ret);
|
const socket_fd = i32(socket_ret);
|
||||||
|
|
||||||
const connect_ret = if (addr.family == linux.AF_INET) {
|
const connect_ret = if (addr.family == linux.AF_INET) x: {
|
||||||
var os_addr: linux.sockaddr_in = undefined;
|
var os_addr: linux.sockaddr_in = undefined;
|
||||||
os_addr.family = addr.family;
|
os_addr.family = addr.family;
|
||||||
os_addr.port = endian.swapIfLe(u16, port);
|
os_addr.port = endian.swapIfLe(u16, port);
|
||||||
@memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
|
@memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
|
||||||
@memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero)));
|
@memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero)));
|
||||||
linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in))
|
break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in));
|
||||||
} else if (addr.family == linux.AF_INET6) {
|
} else if (addr.family == linux.AF_INET6) x: {
|
||||||
var os_addr: linux.sockaddr_in6 = undefined;
|
var os_addr: linux.sockaddr_in6 = undefined;
|
||||||
os_addr.family = addr.family;
|
os_addr.family = addr.family;
|
||||||
os_addr.port = endian.swapIfLe(u16, port);
|
os_addr.port = endian.swapIfLe(u16, port);
|
||||||
os_addr.flowinfo = 0;
|
os_addr.flowinfo = 0;
|
||||||
os_addr.scope_id = addr.scope_id;
|
os_addr.scope_id = addr.scope_id;
|
||||||
@memcpy(&os_addr.addr[0], &addr.addr[0], 16);
|
@memcpy(&os_addr.addr[0], &addr.addr[0], 16);
|
||||||
linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6))
|
break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6));
|
||||||
} else {
|
} else {
|
||||||
unreachable
|
unreachable;
|
||||||
};
|
};
|
||||||
const connect_err = linux.getErrno(connect_ret);
|
const connect_err = linux.getErrno(connect_ret);
|
||||||
if (connect_err > 0) {
|
if (connect_err > 0) {
|
||||||
@ -165,13 +165,13 @@ pub fn parseIpLiteral(buf: []const u8) -> %Address {
|
|||||||
fn hexDigit(c: u8) -> u8 {
|
fn hexDigit(c: u8) -> u8 {
|
||||||
// TODO use switch with range
|
// TODO use switch with range
|
||||||
if ('0' <= c and c <= '9') {
|
if ('0' <= c and c <= '9') {
|
||||||
c - '0'
|
return c - '0';
|
||||||
} else if ('A' <= c and c <= 'Z') {
|
} else if ('A' <= c and c <= 'Z') {
|
||||||
c - 'A' + 10
|
return c - 'A' + 10;
|
||||||
} else if ('a' <= c and c <= 'z') {
|
} else if ('a' <= c and c <= 'z') {
|
||||||
c - 'a' + 10
|
return c - 'a' + 10;
|
||||||
} else {
|
} else {
|
||||||
@maxValue(u8)
|
return @maxValue(u8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ pub const ChildProcess = struct {
|
|||||||
return self.spawnWindows();
|
return self.spawnWindows();
|
||||||
} else {
|
} else {
|
||||||
return self.spawnPosix();
|
return self.spawnPosix();
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawnAndWait(self: &ChildProcess) -> %Term {
|
pub fn spawnAndWait(self: &ChildProcess) -> %Term {
|
||||||
@ -249,12 +249,12 @@ pub const ChildProcess = struct {
|
|||||||
fn waitUnwrappedWindows(self: &ChildProcess) -> %void {
|
fn waitUnwrappedWindows(self: &ChildProcess) -> %void {
|
||||||
const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
|
const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
|
||||||
|
|
||||||
self.term = (%Term)({
|
self.term = (%Term)(x: {
|
||||||
var exit_code: windows.DWORD = undefined;
|
var exit_code: windows.DWORD = undefined;
|
||||||
if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
|
if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
|
||||||
Term { .Unknown = 0 }
|
break :x Term { .Unknown = 0 };
|
||||||
} else {
|
} else {
|
||||||
Term { .Exited = @bitCast(i32, exit_code)}
|
break :x Term { .Exited = @bitCast(i32, exit_code)};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -300,7 +300,7 @@ pub const ChildProcess = struct {
|
|||||||
defer {
|
defer {
|
||||||
os.close(self.err_pipe[0]);
|
os.close(self.err_pipe[0]);
|
||||||
os.close(self.err_pipe[1]);
|
os.close(self.err_pipe[1]);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Write @maxValue(ErrInt) to the write end of the err_pipe. This is after
|
// Write @maxValue(ErrInt) to the write end of the err_pipe. This is after
|
||||||
// waitpid, so this write is guaranteed to be after the child
|
// waitpid, so this write is guaranteed to be after the child
|
||||||
@ -319,15 +319,15 @@ pub const ChildProcess = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn statusToTerm(status: i32) -> Term {
|
fn statusToTerm(status: i32) -> Term {
|
||||||
return if (posix.WIFEXITED(status)) {
|
return if (posix.WIFEXITED(status))
|
||||||
Term { .Exited = posix.WEXITSTATUS(status) }
|
Term { .Exited = posix.WEXITSTATUS(status) }
|
||||||
} else if (posix.WIFSIGNALED(status)) {
|
else if (posix.WIFSIGNALED(status))
|
||||||
Term { .Signal = posix.WTERMSIG(status) }
|
Term { .Signal = posix.WTERMSIG(status) }
|
||||||
} else if (posix.WIFSTOPPED(status)) {
|
else if (posix.WIFSTOPPED(status))
|
||||||
Term { .Stopped = posix.WSTOPSIG(status) }
|
Term { .Stopped = posix.WSTOPSIG(status) }
|
||||||
} else {
|
else
|
||||||
Term { .Unknown = status }
|
Term { .Unknown = status }
|
||||||
};
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawnPosix(self: &ChildProcess) -> %void {
|
fn spawnPosix(self: &ChildProcess) -> %void {
|
||||||
@ -344,22 +344,22 @@ pub const ChildProcess = struct {
|
|||||||
%defer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
|
%defer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
|
||||||
|
|
||||||
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
|
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
|
||||||
const dev_null_fd = if (any_ignore) {
|
const dev_null_fd = if (any_ignore)
|
||||||
%return os.posixOpen("/dev/null", posix.O_RDWR, 0, null)
|
%return os.posixOpen("/dev/null", posix.O_RDWR, 0, null)
|
||||||
} else {
|
else
|
||||||
undefined
|
undefined
|
||||||
};
|
;
|
||||||
defer { if (any_ignore) os.close(dev_null_fd); };
|
defer { if (any_ignore) os.close(dev_null_fd); }
|
||||||
|
|
||||||
var env_map_owned: BufMap = undefined;
|
var env_map_owned: BufMap = undefined;
|
||||||
var we_own_env_map: bool = undefined;
|
var we_own_env_map: bool = undefined;
|
||||||
const env_map = if (self.env_map) |env_map| {
|
const env_map = if (self.env_map) |env_map| x: {
|
||||||
we_own_env_map = false;
|
we_own_env_map = false;
|
||||||
env_map
|
break :x env_map;
|
||||||
} else {
|
} else x: {
|
||||||
we_own_env_map = true;
|
we_own_env_map = true;
|
||||||
env_map_owned = %return os.getEnvMap(self.allocator);
|
env_map_owned = %return os.getEnvMap(self.allocator);
|
||||||
&env_map_owned
|
break :x &env_map_owned;
|
||||||
};
|
};
|
||||||
defer { if (we_own_env_map) env_map_owned.deinit(); }
|
defer { if (we_own_env_map) env_map_owned.deinit(); }
|
||||||
|
|
||||||
@ -450,13 +450,13 @@ pub const ChildProcess = struct {
|
|||||||
self.stdout_behavior == StdIo.Ignore or
|
self.stdout_behavior == StdIo.Ignore or
|
||||||
self.stderr_behavior == StdIo.Ignore);
|
self.stderr_behavior == StdIo.Ignore);
|
||||||
|
|
||||||
const nul_handle = if (any_ignore) {
|
const nul_handle = if (any_ignore)
|
||||||
%return os.windowsOpen("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,
|
%return os.windowsOpen("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,
|
||||||
windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null)
|
windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null)
|
||||||
} else {
|
else
|
||||||
undefined
|
undefined
|
||||||
};
|
;
|
||||||
defer { if (any_ignore) os.close(nul_handle); };
|
defer { if (any_ignore) os.close(nul_handle); }
|
||||||
if (any_ignore) {
|
if (any_ignore) {
|
||||||
%return windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
|
%return windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
|
||||||
}
|
}
|
||||||
@ -542,30 +542,30 @@ pub const ChildProcess = struct {
|
|||||||
};
|
};
|
||||||
var piProcInfo: windows.PROCESS_INFORMATION = undefined;
|
var piProcInfo: windows.PROCESS_INFORMATION = undefined;
|
||||||
|
|
||||||
const cwd_slice = if (self.cwd) |cwd| {
|
const cwd_slice = if (self.cwd) |cwd|
|
||||||
%return cstr.addNullByte(self.allocator, cwd)
|
%return cstr.addNullByte(self.allocator, cwd)
|
||||||
} else {
|
else
|
||||||
null
|
null
|
||||||
};
|
;
|
||||||
defer if (cwd_slice) |cwd| self.allocator.free(cwd);
|
defer if (cwd_slice) |cwd| self.allocator.free(cwd);
|
||||||
const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
|
const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
|
||||||
|
|
||||||
const maybe_envp_buf = if (self.env_map) |env_map| {
|
const maybe_envp_buf = if (self.env_map) |env_map|
|
||||||
%return os.createWindowsEnvBlock(self.allocator, env_map)
|
%return os.createWindowsEnvBlock(self.allocator, env_map)
|
||||||
} else {
|
else
|
||||||
null
|
null
|
||||||
};
|
;
|
||||||
defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
|
defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
|
||||||
const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
|
const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
|
||||||
|
|
||||||
// the cwd set in ChildProcess is in effect when choosing the executable path
|
// the cwd set in ChildProcess is in effect when choosing the executable path
|
||||||
// to match posix semantics
|
// to match posix semantics
|
||||||
const app_name = if (self.cwd) |cwd| {
|
const app_name = if (self.cwd) |cwd| x: {
|
||||||
const resolved = %return os.path.resolve(self.allocator, cwd, self.argv[0]);
|
const resolved = %return os.path.resolve(self.allocator, cwd, self.argv[0]);
|
||||||
defer self.allocator.free(resolved);
|
defer self.allocator.free(resolved);
|
||||||
%return cstr.addNullByte(self.allocator, resolved)
|
break :x %return cstr.addNullByte(self.allocator, resolved);
|
||||||
} else {
|
} else x: {
|
||||||
%return cstr.addNullByte(self.allocator, self.argv[0])
|
break :x %return cstr.addNullByte(self.allocator, self.argv[0]);
|
||||||
};
|
};
|
||||||
defer self.allocator.free(app_name);
|
defer self.allocator.free(app_name);
|
||||||
|
|
||||||
@ -741,7 +741,7 @@ fn makePipe() -> %[2]i32 {
|
|||||||
return switch (err) {
|
return switch (err) {
|
||||||
posix.EMFILE, posix.ENFILE => error.SystemResources,
|
posix.EMFILE, posix.ENFILE => error.SystemResources,
|
||||||
else => os.unexpectedErrorPosix(err),
|
else => os.unexpectedErrorPosix(err),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
return fds;
|
return fds;
|
||||||
}
|
}
|
||||||
@ -800,10 +800,10 @@ fn handleTerm(pid: i32, status: i32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sigchld_set = {
|
const sigchld_set = x: {
|
||||||
var signal_set = posix.empty_sigset;
|
var signal_set = posix.empty_sigset;
|
||||||
posix.sigaddset(&signal_set, posix.SIGCHLD);
|
posix.sigaddset(&signal_set, posix.SIGCHLD);
|
||||||
signal_set
|
break :x signal_set;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn block_SIGCHLD() {
|
fn block_SIGCHLD() {
|
||||||
|
@ -97,63 +97,63 @@ pub const SIGINFO = 29; /// information request
|
|||||||
pub const SIGUSR1 = 30; /// user defined signal 1
|
pub const SIGUSR1 = 30; /// user defined signal 1
|
||||||
pub const SIGUSR2 = 31; /// user defined signal 2
|
pub const SIGUSR2 = 31; /// user defined signal 2
|
||||||
|
|
||||||
fn wstatus(x: i32) -> i32 { x & 0o177 }
|
fn wstatus(x: i32) -> i32 { return x & 0o177; }
|
||||||
const wstopped = 0o177;
|
const wstopped = 0o177;
|
||||||
pub fn WEXITSTATUS(x: i32) -> i32 { x >> 8 }
|
pub fn WEXITSTATUS(x: i32) -> i32 { return x >> 8; }
|
||||||
pub fn WTERMSIG(x: i32) -> i32 { wstatus(x) }
|
pub fn WTERMSIG(x: i32) -> i32 { return wstatus(x); }
|
||||||
pub fn WSTOPSIG(x: i32) -> i32 { x >> 8 }
|
pub fn WSTOPSIG(x: i32) -> i32 { return x >> 8; }
|
||||||
pub fn WIFEXITED(x: i32) -> bool { wstatus(x) == 0 }
|
pub fn WIFEXITED(x: i32) -> bool { return wstatus(x) == 0; }
|
||||||
pub fn WIFSTOPPED(x: i32) -> bool { wstatus(x) == wstopped and WSTOPSIG(x) != 0x13 }
|
pub fn WIFSTOPPED(x: i32) -> bool { return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; }
|
||||||
pub fn WIFSIGNALED(x: i32) -> bool { wstatus(x) != wstopped and wstatus(x) != 0 }
|
pub fn WIFSIGNALED(x: i32) -> bool { return wstatus(x) != wstopped and wstatus(x) != 0; }
|
||||||
|
|
||||||
/// Get the errno from a syscall return value, or 0 for no error.
|
/// Get the errno from a syscall return value, or 0 for no error.
|
||||||
pub fn getErrno(r: usize) -> usize {
|
pub fn getErrno(r: usize) -> usize {
|
||||||
const signed_r = @bitCast(isize, r);
|
const signed_r = @bitCast(isize, r);
|
||||||
if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0
|
return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(fd: i32) -> usize {
|
pub fn close(fd: i32) -> usize {
|
||||||
errnoWrap(c.close(fd))
|
return errnoWrap(c.close(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn abort() -> noreturn {
|
pub fn abort() -> noreturn {
|
||||||
c.abort()
|
return c.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(code: i32) -> noreturn {
|
pub fn exit(code: i32) -> noreturn {
|
||||||
c.exit(code)
|
return c.exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isatty(fd: i32) -> bool {
|
pub fn isatty(fd: i32) -> bool {
|
||||||
c.isatty(fd) != 0
|
return 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$INODE64"(fd, buf))
|
return errnoWrap(c.@"fstat$INODE64"(fd, buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lseek(fd: i32, offset: isize, whence: c_int) -> usize {
|
pub fn lseek(fd: i32, offset: isize, whence: c_int) -> usize {
|
||||||
errnoWrap(c.lseek(fd, offset, whence))
|
return errnoWrap(c.lseek(fd, offset, whence));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(path: &const u8, flags: u32, mode: usize) -> usize {
|
pub fn open(path: &const u8, flags: u32, mode: usize) -> usize {
|
||||||
errnoWrap(c.open(path, @bitCast(c_int, flags), mode))
|
return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raise(sig: i32) -> usize {
|
pub fn raise(sig: i32) -> usize {
|
||||||
errnoWrap(c.raise(sig))
|
return errnoWrap(c.raise(sig));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(fd: i32, buf: &u8, nbyte: usize) -> usize {
|
pub fn read(fd: i32, buf: &u8, nbyte: usize) -> usize {
|
||||||
errnoWrap(c.read(fd, @ptrCast(&c_void, buf), nbyte))
|
return errnoWrap(c.read(fd, @ptrCast(&c_void, buf), nbyte));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stat(noalias path: &const u8, noalias buf: &stat) -> usize {
|
pub fn stat(noalias path: &const u8, noalias buf: &stat) -> usize {
|
||||||
errnoWrap(c.stat(path, buf))
|
return errnoWrap(c.stat(path, buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(fd: i32, buf: &const u8, nbyte: usize) -> usize {
|
pub fn write(fd: i32, buf: &const u8, nbyte: usize) -> usize {
|
||||||
errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte))
|
return errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32,
|
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32,
|
||||||
@ -166,79 +166,79 @@ pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn munmap(address: &u8, length: usize) -> usize {
|
pub fn munmap(address: &u8, length: usize) -> usize {
|
||||||
errnoWrap(c.munmap(@ptrCast(&c_void, address), length))
|
return errnoWrap(c.munmap(@ptrCast(&c_void, address), length));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unlink(path: &const u8) -> usize {
|
pub fn unlink(path: &const u8) -> usize {
|
||||||
errnoWrap(c.unlink(path))
|
return errnoWrap(c.unlink(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getcwd(buf: &u8, size: usize) -> usize {
|
pub fn getcwd(buf: &u8, size: usize) -> usize {
|
||||||
if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0
|
return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn waitpid(pid: i32, status: &i32, options: u32) -> usize {
|
pub fn waitpid(pid: i32, status: &i32, options: u32) -> usize {
|
||||||
comptime assert(i32.bit_count == c_int.bit_count);
|
comptime assert(i32.bit_count == c_int.bit_count);
|
||||||
errnoWrap(c.waitpid(pid, @ptrCast(&c_int, status), @bitCast(c_int, options)))
|
return errnoWrap(c.waitpid(pid, @ptrCast(&c_int, status), @bitCast(c_int, options)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fork() -> usize {
|
pub fn fork() -> usize {
|
||||||
errnoWrap(c.fork())
|
return errnoWrap(c.fork());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pipe(fds: &[2]i32) -> usize {
|
pub fn pipe(fds: &[2]i32) -> usize {
|
||||||
comptime assert(i32.bit_count == c_int.bit_count);
|
comptime assert(i32.bit_count == c_int.bit_count);
|
||||||
errnoWrap(c.pipe(@ptrCast(&c_int, fds)))
|
return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mkdir(path: &const u8, mode: u32) -> usize {
|
pub fn mkdir(path: &const u8, mode: u32) -> usize {
|
||||||
errnoWrap(c.mkdir(path, mode))
|
return errnoWrap(c.mkdir(path, mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn symlink(existing: &const u8, new: &const u8) -> usize {
|
pub fn symlink(existing: &const u8, new: &const u8) -> usize {
|
||||||
errnoWrap(c.symlink(existing, new))
|
return errnoWrap(c.symlink(existing, new));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename(old: &const u8, new: &const u8) -> usize {
|
pub fn rename(old: &const u8, new: &const u8) -> usize {
|
||||||
errnoWrap(c.rename(old, new))
|
return errnoWrap(c.rename(old, new));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chdir(path: &const u8) -> usize {
|
pub fn chdir(path: &const u8) -> usize {
|
||||||
errnoWrap(c.chdir(path))
|
return errnoWrap(c.chdir(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8)
|
pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8)
|
||||||
-> usize
|
-> usize
|
||||||
{
|
{
|
||||||
errnoWrap(c.execve(path, argv, envp))
|
return errnoWrap(c.execve(path, argv, envp));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dup2(old: i32, new: i32) -> usize {
|
pub fn dup2(old: i32, new: i32) -> usize {
|
||||||
errnoWrap(c.dup2(old, new))
|
return errnoWrap(c.dup2(old, new));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {
|
pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {
|
||||||
errnoWrap(c.readlink(path, buf_ptr, buf_len))
|
return errnoWrap(c.readlink(path, buf_ptr, buf_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nanosleep(req: &const timespec, rem: ?×pec) -> usize {
|
pub fn nanosleep(req: &const timespec, rem: ?×pec) -> usize {
|
||||||
errnoWrap(c.nanosleep(req, rem))
|
return errnoWrap(c.nanosleep(req, rem));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) -> usize {
|
pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) -> usize {
|
||||||
if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0
|
return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setreuid(ruid: u32, euid: u32) -> usize {
|
pub fn setreuid(ruid: u32, euid: u32) -> usize {
|
||||||
errnoWrap(c.setreuid(ruid, euid))
|
return errnoWrap(c.setreuid(ruid, euid));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setregid(rgid: u32, egid: u32) -> usize {
|
pub fn setregid(rgid: u32, egid: u32) -> usize {
|
||||||
errnoWrap(c.setregid(rgid, egid))
|
return errnoWrap(c.setregid(rgid, egid));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {
|
pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {
|
||||||
errnoWrap(c.sigprocmask(@bitCast(c_int, flags), set, oldset))
|
return errnoWrap(c.sigprocmask(@bitCast(c_int, flags), set, oldset));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {
|
pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {
|
||||||
@ -285,9 +285,5 @@ pub fn sigaddset(set: &sigset_t, signo: u5) {
|
|||||||
/// that the kernel represents it to libc. Errno was a mistake, let's make
|
/// that the kernel represents it to libc. Errno was a mistake, let's make
|
||||||
/// it go away forever.
|
/// it go away forever.
|
||||||
fn errnoWrap(value: isize) -> usize {
|
fn errnoWrap(value: isize) -> usize {
|
||||||
@bitCast(usize, if (value == -1) {
|
return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);
|
||||||
-isize(*c._errno())
|
|
||||||
} else {
|
|
||||||
value
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {
|
|||||||
posix.EFAULT => unreachable,
|
posix.EFAULT => unreachable,
|
||||||
posix.EINTR => continue,
|
posix.EINTR => continue,
|
||||||
else => unexpectedErrorPosix(err),
|
else => unexpectedErrorPosix(err),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
@ -151,18 +151,17 @@ pub coldcc fn exit(status: i32) -> noreturn {
|
|||||||
}
|
}
|
||||||
switch (builtin.os) {
|
switch (builtin.os) {
|
||||||
Os.linux, Os.darwin, Os.macosx, Os.ios => {
|
Os.linux, Os.darwin, Os.macosx, Os.ios => {
|
||||||
posix.exit(status)
|
posix.exit(status);
|
||||||
},
|
},
|
||||||
Os.windows => {
|
Os.windows => {
|
||||||
// Map a possibly negative status code to a non-negative status for the systems default
|
// Map a possibly negative status code to a non-negative status for the systems default
|
||||||
// integer width.
|
// integer width.
|
||||||
const p_status = if (@sizeOf(c_uint) < @sizeOf(u32)) {
|
const p_status = if (@sizeOf(c_uint) < @sizeOf(u32))
|
||||||
@truncate(c_uint, @bitCast(u32, status))
|
@truncate(c_uint, @bitCast(u32, status))
|
||||||
} else {
|
else
|
||||||
c_uint(@bitCast(u32, status))
|
c_uint(@bitCast(u32, status));
|
||||||
};
|
|
||||||
|
|
||||||
windows.ExitProcess(p_status)
|
windows.ExitProcess(p_status);
|
||||||
},
|
},
|
||||||
else => @compileError("Unsupported OS"),
|
else => @compileError("Unsupported OS"),
|
||||||
}
|
}
|
||||||
@ -289,7 +288,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al
|
|||||||
posix.EPERM => error.AccessDenied,
|
posix.EPERM => error.AccessDenied,
|
||||||
posix.EEXIST => error.PathAlreadyExists,
|
posix.EEXIST => error.PathAlreadyExists,
|
||||||
else => unexpectedErrorPosix(err),
|
else => unexpectedErrorPosix(err),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
return i32(result);
|
return i32(result);
|
||||||
}
|
}
|
||||||
@ -680,7 +679,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) -> %void
|
|||||||
windows.ERROR.ACCESS_DENIED => error.AccessDenied,
|
windows.ERROR.ACCESS_DENIED => error.AccessDenied,
|
||||||
windows.ERROR.FILENAME_EXCED_RANGE, windows.ERROR.INVALID_PARAMETER => error.NameTooLong,
|
windows.ERROR.FILENAME_EXCED_RANGE, windows.ERROR.INVALID_PARAMETER => error.NameTooLong,
|
||||||
else => unexpectedErrorWindows(err),
|
else => unexpectedErrorWindows(err),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1006,7 +1005,7 @@ pub const Dir = struct {
|
|||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
else => return unexpectedErrorPosix(err),
|
else => return unexpectedErrorPosix(err),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
return null;
|
return null;
|
||||||
|
136
std/os/linux.zig
136
std/os/linux.zig
@ -367,14 +367,14 @@ pub const TFD_CLOEXEC = O_CLOEXEC;
|
|||||||
pub const TFD_TIMER_ABSTIME = 1;
|
pub const TFD_TIMER_ABSTIME = 1;
|
||||||
pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
|
pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
|
||||||
|
|
||||||
fn unsigned(s: i32) -> u32 { @bitCast(u32, s) }
|
fn unsigned(s: i32) -> u32 { return @bitCast(u32, s); }
|
||||||
fn signed(s: u32) -> i32 { @bitCast(i32, s) }
|
fn signed(s: u32) -> i32 { return @bitCast(i32, s); }
|
||||||
pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) }
|
pub fn WEXITSTATUS(s: i32) -> i32 { return signed((unsigned(s) & 0xff00) >> 8); }
|
||||||
pub fn WTERMSIG(s: i32) -> i32 { signed(unsigned(s) & 0x7f) }
|
pub fn WTERMSIG(s: i32) -> i32 { return signed(unsigned(s) & 0x7f); }
|
||||||
pub fn WSTOPSIG(s: i32) -> i32 { WEXITSTATUS(s) }
|
pub fn WSTOPSIG(s: i32) -> i32 { return WEXITSTATUS(s); }
|
||||||
pub fn WIFEXITED(s: i32) -> bool { WTERMSIG(s) == 0 }
|
pub fn WIFEXITED(s: i32) -> bool { return WTERMSIG(s) == 0; }
|
||||||
pub fn WIFSTOPPED(s: i32) -> bool { (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00 }
|
pub fn WIFSTOPPED(s: i32) -> bool { return (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00; }
|
||||||
pub fn WIFSIGNALED(s: i32) -> bool { (unsigned(s)&0xffff)-%1 < 0xff }
|
pub fn WIFSIGNALED(s: i32) -> bool { return (unsigned(s)&0xffff)-%1 < 0xff; }
|
||||||
|
|
||||||
|
|
||||||
pub const winsize = extern struct {
|
pub const winsize = extern struct {
|
||||||
@ -387,31 +387,31 @@ pub const winsize = extern struct {
|
|||||||
/// Get the errno from a syscall return value, or 0 for no error.
|
/// Get the errno from a syscall return value, or 0 for no error.
|
||||||
pub fn getErrno(r: usize) -> usize {
|
pub fn getErrno(r: usize) -> usize {
|
||||||
const signed_r = @bitCast(isize, r);
|
const signed_r = @bitCast(isize, r);
|
||||||
if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0
|
return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dup2(old: i32, new: i32) -> usize {
|
pub fn dup2(old: i32, new: i32) -> usize {
|
||||||
arch.syscall2(arch.SYS_dup2, usize(old), usize(new))
|
return arch.syscall2(arch.SYS_dup2, usize(old), usize(new));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chdir(path: &const u8) -> usize {
|
pub fn chdir(path: &const u8) -> usize {
|
||||||
arch.syscall1(arch.SYS_chdir, @ptrToInt(path))
|
return arch.syscall1(arch.SYS_chdir, @ptrToInt(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {
|
pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {
|
||||||
arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp))
|
return arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fork() -> usize {
|
pub fn fork() -> usize {
|
||||||
arch.syscall0(arch.SYS_fork)
|
return arch.syscall0(arch.SYS_fork);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getcwd(buf: &u8, size: usize) -> usize {
|
pub fn getcwd(buf: &u8, size: usize) -> usize {
|
||||||
arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size)
|
return arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize {
|
pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize {
|
||||||
arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count)
|
return arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isatty(fd: i32) -> bool {
|
pub fn isatty(fd: i32) -> bool {
|
||||||
@ -420,123 +420,123 @@ pub fn isatty(fd: i32) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {
|
pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {
|
||||||
arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len)
|
return arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mkdir(path: &const u8, mode: u32) -> usize {
|
pub fn mkdir(path: &const u8, mode: u32) -> usize {
|
||||||
arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode)
|
return arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize)
|
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize)
|
||||||
-> usize
|
-> usize
|
||||||
{
|
{
|
||||||
arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
|
return arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
|
||||||
@bitCast(usize, offset))
|
@bitCast(usize, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn munmap(address: &u8, length: usize) -> usize {
|
pub fn munmap(address: &u8, length: usize) -> usize {
|
||||||
arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length)
|
return arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
|
pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
|
||||||
arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count)
|
return arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rmdir(path: &const u8) -> usize {
|
pub fn rmdir(path: &const u8) -> usize {
|
||||||
arch.syscall1(arch.SYS_rmdir, @ptrToInt(path))
|
return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn symlink(existing: &const u8, new: &const u8) -> usize {
|
pub fn symlink(existing: &const u8, new: &const u8) -> usize {
|
||||||
arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new))
|
return arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {
|
pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {
|
||||||
arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset)
|
return arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pipe(fd: &[2]i32) -> usize {
|
pub fn pipe(fd: &[2]i32) -> usize {
|
||||||
pipe2(fd, 0)
|
return pipe2(fd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pipe2(fd: &[2]i32, flags: usize) -> usize {
|
pub fn pipe2(fd: &[2]i32, flags: usize) -> usize {
|
||||||
arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags)
|
return arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {
|
pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {
|
||||||
arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count)
|
return arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize {
|
pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize {
|
||||||
arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset)
|
return arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename(old: &const u8, new: &const u8) -> usize {
|
pub fn rename(old: &const u8, new: &const u8) -> usize {
|
||||||
arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new))
|
return arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(path: &const u8, flags: u32, perm: usize) -> usize {
|
pub fn open(path: &const u8, flags: u32, perm: usize) -> usize {
|
||||||
arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm)
|
return arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(path: &const u8, perm: usize) -> usize {
|
pub fn create(path: &const u8, perm: usize) -> usize {
|
||||||
arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm)
|
return arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize {
|
pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize {
|
||||||
arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode)
|
return arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(fd: i32) -> usize {
|
pub fn close(fd: i32) -> usize {
|
||||||
arch.syscall1(arch.SYS_close, usize(fd))
|
return arch.syscall1(arch.SYS_close, usize(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lseek(fd: i32, offset: isize, ref_pos: usize) -> usize {
|
pub fn lseek(fd: i32, offset: isize, ref_pos: usize) -> usize {
|
||||||
arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos)
|
return arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(status: i32) -> noreturn {
|
pub fn exit(status: i32) -> noreturn {
|
||||||
_ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status)));
|
_ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status)));
|
||||||
unreachable
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize {
|
pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize {
|
||||||
arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags))
|
return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kill(pid: i32, sig: i32) -> usize {
|
pub fn kill(pid: i32, sig: i32) -> usize {
|
||||||
arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig))
|
return arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unlink(path: &const u8) -> usize {
|
pub fn unlink(path: &const u8) -> usize {
|
||||||
arch.syscall1(arch.SYS_unlink, @ptrToInt(path))
|
return arch.syscall1(arch.SYS_unlink, @ptrToInt(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize {
|
pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize {
|
||||||
arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0)
|
return arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nanosleep(req: &const timespec, rem: ?×pec) -> usize {
|
pub fn nanosleep(req: &const timespec, rem: ?×pec) -> usize {
|
||||||
arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem))
|
return arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setuid(uid: u32) -> usize {
|
pub fn setuid(uid: u32) -> usize {
|
||||||
arch.syscall1(arch.SYS_setuid, uid)
|
return arch.syscall1(arch.SYS_setuid, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setgid(gid: u32) -> usize {
|
pub fn setgid(gid: u32) -> usize {
|
||||||
arch.syscall1(arch.SYS_setgid, gid)
|
return arch.syscall1(arch.SYS_setgid, gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setreuid(ruid: u32, euid: u32) -> usize {
|
pub fn setreuid(ruid: u32, euid: u32) -> usize {
|
||||||
arch.syscall2(arch.SYS_setreuid, ruid, euid)
|
return arch.syscall2(arch.SYS_setreuid, ruid, euid);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setregid(rgid: u32, egid: u32) -> usize {
|
pub fn setregid(rgid: u32, egid: u32) -> usize {
|
||||||
arch.syscall2(arch.SYS_setregid, rgid, egid)
|
return arch.syscall2(arch.SYS_setregid, rgid, egid);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {
|
pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {
|
||||||
arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8)
|
return arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {
|
pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {
|
||||||
@ -652,69 +652,69 @@ pub const iovec = extern struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
|
pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
|
||||||
arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len))
|
return arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
|
pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
|
||||||
arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len))
|
return arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize {
|
pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize {
|
||||||
arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol))
|
return arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) -> usize {
|
pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) -> usize {
|
||||||
arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen))
|
return arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) -> usize {
|
pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) -> usize {
|
||||||
arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen))
|
return arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) -> usize {
|
pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) -> usize {
|
||||||
arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags)
|
return arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {
|
pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {
|
||||||
arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len))
|
return arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) -> usize {
|
pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) -> usize {
|
||||||
arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags)
|
return arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
|
pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
|
||||||
noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize
|
noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize
|
||||||
{
|
{
|
||||||
arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen))
|
return arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdown(fd: i32, how: i32) -> usize {
|
pub fn shutdown(fd: i32, how: i32) -> usize {
|
||||||
arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how))
|
return arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {
|
pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {
|
||||||
arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len))
|
return arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listen(fd: i32, backlog: i32) -> usize {
|
pub fn listen(fd: i32, backlog: i32) -> usize {
|
||||||
arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog))
|
return arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) -> usize {
|
pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) -> usize {
|
||||||
arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen))
|
return arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> usize {
|
pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> usize {
|
||||||
arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0]))
|
return arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
|
pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
|
||||||
accept4(fd, addr, len, 0)
|
return accept4(fd, addr, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) -> usize {
|
pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) -> usize {
|
||||||
arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags)
|
return arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// error NameTooLong;
|
// error NameTooLong;
|
||||||
@ -749,7 +749,7 @@ pub const Stat = arch.Stat;
|
|||||||
pub const timespec = arch.timespec;
|
pub const timespec = arch.timespec;
|
||||||
|
|
||||||
pub fn fstat(fd: i32, stat_buf: &Stat) -> usize {
|
pub fn fstat(fd: i32, stat_buf: &Stat) -> usize {
|
||||||
arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf))
|
return arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const epoll_data = u64;
|
pub const epoll_data = u64;
|
||||||
@ -760,19 +760,19 @@ pub const epoll_event = extern struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn epoll_create() -> usize {
|
pub fn epoll_create() -> usize {
|
||||||
arch.syscall1(arch.SYS_epoll_create, usize(1))
|
return arch.syscall1(arch.SYS_epoll_create, usize(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) -> usize {
|
pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) -> usize {
|
||||||
arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev))
|
return arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: i32, timeout: i32) -> usize {
|
pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: i32, timeout: i32) -> usize {
|
||||||
arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout))
|
return arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn timerfd_create(clockid: i32, flags: u32) -> usize {
|
pub fn timerfd_create(clockid: i32, flags: u32) -> usize {
|
||||||
arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags))
|
return arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const itimerspec = extern struct {
|
pub const itimerspec = extern struct {
|
||||||
@ -781,11 +781,11 @@ pub const itimerspec = extern struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) -> usize {
|
pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) -> usize {
|
||||||
arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value))
|
return arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) -> usize {
|
pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) -> usize {
|
||||||
arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value))
|
return arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "import linux_test" {
|
test "import linux_test" {
|
||||||
|
@ -371,52 +371,52 @@ pub const F_GETOWN_EX = 16;
|
|||||||
pub const F_GETOWNER_UIDS = 17;
|
pub const F_GETOWNER_UIDS = 17;
|
||||||
|
|
||||||
pub fn syscall0(number: usize) -> usize {
|
pub fn syscall0(number: usize) -> usize {
|
||||||
asm volatile ("syscall"
|
return asm volatile ("syscall"
|
||||||
: [ret] "={rax}" (-> usize)
|
: [ret] "={rax}" (-> usize)
|
||||||
: [number] "{rax}" (number)
|
: [number] "{rax}" (number)
|
||||||
: "rcx", "r11")
|
: "rcx", "r11");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syscall1(number: usize, arg1: usize) -> usize {
|
pub fn syscall1(number: usize, arg1: usize) -> usize {
|
||||||
asm volatile ("syscall"
|
return asm volatile ("syscall"
|
||||||
: [ret] "={rax}" (-> usize)
|
: [ret] "={rax}" (-> usize)
|
||||||
: [number] "{rax}" (number),
|
: [number] "{rax}" (number),
|
||||||
[arg1] "{rdi}" (arg1)
|
[arg1] "{rdi}" (arg1)
|
||||||
: "rcx", "r11")
|
: "rcx", "r11");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize {
|
pub fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize {
|
||||||
asm volatile ("syscall"
|
return asm volatile ("syscall"
|
||||||
: [ret] "={rax}" (-> usize)
|
: [ret] "={rax}" (-> usize)
|
||||||
: [number] "{rax}" (number),
|
: [number] "{rax}" (number),
|
||||||
[arg1] "{rdi}" (arg1),
|
[arg1] "{rdi}" (arg1),
|
||||||
[arg2] "{rsi}" (arg2)
|
[arg2] "{rsi}" (arg2)
|
||||||
: "rcx", "r11")
|
: "rcx", "r11");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
|
pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
|
||||||
asm volatile ("syscall"
|
return asm volatile ("syscall"
|
||||||
: [ret] "={rax}" (-> usize)
|
: [ret] "={rax}" (-> usize)
|
||||||
: [number] "{rax}" (number),
|
: [number] "{rax}" (number),
|
||||||
[arg1] "{rdi}" (arg1),
|
[arg1] "{rdi}" (arg1),
|
||||||
[arg2] "{rsi}" (arg2),
|
[arg2] "{rsi}" (arg2),
|
||||||
[arg3] "{rdx}" (arg3)
|
[arg3] "{rdx}" (arg3)
|
||||||
: "rcx", "r11")
|
: "rcx", "r11");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize {
|
pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize {
|
||||||
asm volatile ("syscall"
|
return asm volatile ("syscall"
|
||||||
: [ret] "={rax}" (-> usize)
|
: [ret] "={rax}" (-> usize)
|
||||||
: [number] "{rax}" (number),
|
: [number] "{rax}" (number),
|
||||||
[arg1] "{rdi}" (arg1),
|
[arg1] "{rdi}" (arg1),
|
||||||
[arg2] "{rsi}" (arg2),
|
[arg2] "{rsi}" (arg2),
|
||||||
[arg3] "{rdx}" (arg3),
|
[arg3] "{rdx}" (arg3),
|
||||||
[arg4] "{r10}" (arg4)
|
[arg4] "{r10}" (arg4)
|
||||||
: "rcx", "r11")
|
: "rcx", "r11");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize {
|
pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize {
|
||||||
asm volatile ("syscall"
|
return asm volatile ("syscall"
|
||||||
: [ret] "={rax}" (-> usize)
|
: [ret] "={rax}" (-> usize)
|
||||||
: [number] "{rax}" (number),
|
: [number] "{rax}" (number),
|
||||||
[arg1] "{rdi}" (arg1),
|
[arg1] "{rdi}" (arg1),
|
||||||
@ -424,13 +424,13 @@ pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz
|
|||||||
[arg3] "{rdx}" (arg3),
|
[arg3] "{rdx}" (arg3),
|
||||||
[arg4] "{r10}" (arg4),
|
[arg4] "{r10}" (arg4),
|
||||||
[arg5] "{r8}" (arg5)
|
[arg5] "{r8}" (arg5)
|
||||||
: "rcx", "r11")
|
: "rcx", "r11");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
|
pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
|
||||||
arg5: usize, arg6: usize) -> usize
|
arg5: usize, arg6: usize) -> usize
|
||||||
{
|
{
|
||||||
asm volatile ("syscall"
|
return asm volatile ("syscall"
|
||||||
: [ret] "={rax}" (-> usize)
|
: [ret] "={rax}" (-> usize)
|
||||||
: [number] "{rax}" (number),
|
: [number] "{rax}" (number),
|
||||||
[arg1] "{rdi}" (arg1),
|
[arg1] "{rdi}" (arg1),
|
||||||
@ -439,14 +439,14 @@ pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz
|
|||||||
[arg4] "{r10}" (arg4),
|
[arg4] "{r10}" (arg4),
|
||||||
[arg5] "{r8}" (arg5),
|
[arg5] "{r8}" (arg5),
|
||||||
[arg6] "{r9}" (arg6)
|
[arg6] "{r9}" (arg6)
|
||||||
: "rcx", "r11")
|
: "rcx", "r11");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub nakedcc fn restore_rt() {
|
pub nakedcc fn restore_rt() {
|
||||||
asm volatile ("syscall"
|
return asm volatile ("syscall"
|
||||||
:
|
:
|
||||||
: [number] "{rax}" (usize(SYS_rt_sigreturn))
|
: [number] "{rax}" (usize(SYS_rt_sigreturn))
|
||||||
: "rcx", "r11")
|
: "rcx", "r11");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -749,21 +749,19 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8)
|
|||||||
const resolved_to = %return resolveWindows(allocator, [][]const u8{to});
|
const resolved_to = %return resolveWindows(allocator, [][]const u8{to});
|
||||||
defer if (clean_up_resolved_to) allocator.free(resolved_to);
|
defer if (clean_up_resolved_to) allocator.free(resolved_to);
|
||||||
|
|
||||||
const result_is_to = if (drive(resolved_to)) |to_drive| {
|
const result_is_to = if (drive(resolved_to)) |to_drive|
|
||||||
if (drive(resolved_from)) |from_drive| {
|
if (drive(resolved_from)) |from_drive|
|
||||||
asciiUpper(from_drive[0]) != asciiUpper(to_drive[0])
|
asciiUpper(from_drive[0]) != asciiUpper(to_drive[0])
|
||||||
} else {
|
else
|
||||||
true
|
true
|
||||||
}
|
else if (networkShare(resolved_to)) |to_ns|
|
||||||
} else if (networkShare(resolved_to)) |to_ns| {
|
if (networkShare(resolved_from)) |from_ns|
|
||||||
if (networkShare(resolved_from)) |from_ns| {
|
|
||||||
!networkShareServersEql(to_ns, from_ns)
|
!networkShareServersEql(to_ns, from_ns)
|
||||||
} else {
|
else
|
||||||
true
|
true
|
||||||
}
|
else
|
||||||
} else {
|
unreachable;
|
||||||
unreachable
|
|
||||||
};
|
|
||||||
if (result_is_to) {
|
if (result_is_to) {
|
||||||
clean_up_resolved_to = false;
|
clean_up_resolved_to = false;
|
||||||
return resolved_to;
|
return resolved_to;
|
||||||
@ -964,14 +962,16 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
|
|||||||
|
|
||||||
// windows returns \\?\ prepended to the path
|
// windows returns \\?\ prepended to the path
|
||||||
// we strip it because nobody wants \\?\ prepended to their path
|
// we strip it because nobody wants \\?\ prepended to their path
|
||||||
const final_len = if (result > 4 and mem.startsWith(u8, buf, "\\\\?\\")) {
|
const final_len = x: {
|
||||||
var i: usize = 4;
|
if (result > 4 and mem.startsWith(u8, buf, "\\\\?\\")) {
|
||||||
while (i < result) : (i += 1) {
|
var i: usize = 4;
|
||||||
buf[i - 4] = buf[i];
|
while (i < result) : (i += 1) {
|
||||||
|
buf[i - 4] = buf[i];
|
||||||
|
}
|
||||||
|
break :x result - 4;
|
||||||
|
} else {
|
||||||
|
break :x result;
|
||||||
}
|
}
|
||||||
result - 4
|
|
||||||
} else {
|
|
||||||
result
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return allocator.shrink(u8, buf, final_len);
|
return allocator.shrink(u8, buf, final_len);
|
||||||
|
@ -122,7 +122,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
|
|||||||
/// Caller must free result.
|
/// Caller must free result.
|
||||||
pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 {
|
pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 {
|
||||||
// count bytes needed
|
// count bytes needed
|
||||||
const bytes_needed = {
|
const bytes_needed = x: {
|
||||||
var bytes_needed: usize = 1; // 1 for the final null byte
|
var bytes_needed: usize = 1; // 1 for the final null byte
|
||||||
var it = env_map.iterator();
|
var it = env_map.iterator();
|
||||||
while (it.next()) |pair| {
|
while (it.next()) |pair| {
|
||||||
@ -130,7 +130,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap)
|
|||||||
// +1 for null byte
|
// +1 for null byte
|
||||||
bytes_needed += pair.key.len + pair.value.len + 2;
|
bytes_needed += pair.key.len + pair.value.len + 2;
|
||||||
}
|
}
|
||||||
bytes_needed
|
break :x bytes_needed;
|
||||||
};
|
};
|
||||||
const result = %return allocator.alloc(u8, bytes_needed);
|
const result = %return allocator.alloc(u8, bytes_needed);
|
||||||
%defer allocator.free(result);
|
%defer allocator.free(result);
|
||||||
|
28
std/rand.zig
28
std/rand.zig
@ -28,9 +28,9 @@ pub const Rand = struct {
|
|||||||
|
|
||||||
/// Initialize random state with the given seed.
|
/// Initialize random state with the given seed.
|
||||||
pub fn init(seed: usize) -> Rand {
|
pub fn init(seed: usize) -> Rand {
|
||||||
Rand {
|
return Rand {
|
||||||
.rng = Rng.init(seed),
|
.rng = Rng.init(seed),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an integer or boolean with random bits.
|
/// Get an integer or boolean with random bits.
|
||||||
@ -78,13 +78,13 @@ pub const Rand = struct {
|
|||||||
const end_uint = uint(end);
|
const end_uint = uint(end);
|
||||||
const total_range = math.absCast(start) + end_uint;
|
const total_range = math.absCast(start) + end_uint;
|
||||||
const value = r.range(uint, 0, total_range);
|
const value = r.range(uint, 0, total_range);
|
||||||
const result = if (value < end_uint) {
|
const result = if (value < end_uint) x: {
|
||||||
T(value)
|
break :x T(value);
|
||||||
} else if (value == end_uint) {
|
} else if (value == end_uint) x: {
|
||||||
start
|
break :x start;
|
||||||
} else {
|
} else x: {
|
||||||
// Can't overflow because the range is over signed ints
|
// Can't overflow because the range is over signed ints
|
||||||
%%math.negateCast(value - end_uint)
|
break :x %%math.negateCast(value - end_uint);
|
||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
@ -114,13 +114,13 @@ pub const Rand = struct {
|
|||||||
// const rand_bits = r.rng.scalar(int) & mask;
|
// const rand_bits = r.rng.scalar(int) & mask;
|
||||||
// return @float_compose(T, false, 0, rand_bits) - 1.0
|
// return @float_compose(T, false, 0, rand_bits) - 1.0
|
||||||
const int_type = @IntType(false, @sizeOf(T) * 8);
|
const int_type = @IntType(false, @sizeOf(T) * 8);
|
||||||
const precision = if (T == f32) {
|
const precision = if (T == f32)
|
||||||
16777216
|
16777216
|
||||||
} else if (T == f64) {
|
else if (T == f64)
|
||||||
9007199254740992
|
9007199254740992
|
||||||
} else {
|
else
|
||||||
@compileError("unknown floating point type")
|
@compileError("unknown floating point type")
|
||||||
};
|
;
|
||||||
return T(r.range(int_type, 0, precision)) / T(precision);
|
return T(r.range(int_type, 0, precision)) / T(precision);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -133,7 +133,7 @@ fn MersenneTwister(
|
|||||||
comptime t: math.Log2Int(int), comptime c: int,
|
comptime t: math.Log2Int(int), comptime c: int,
|
||||||
comptime l: math.Log2Int(int), comptime f: int) -> type
|
comptime l: math.Log2Int(int), comptime f: int) -> type
|
||||||
{
|
{
|
||||||
struct {
|
return struct {
|
||||||
const Self = this;
|
const Self = this;
|
||||||
|
|
||||||
array: [n]int,
|
array: [n]int,
|
||||||
@ -189,7 +189,7 @@ fn MersenneTwister(
|
|||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "rand float 32" {
|
test "rand float 32" {
|
||||||
|
@ -355,7 +355,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
|
|||||||
// these values will be pulled out to the start of A
|
// these values will be pulled out to the start of A
|
||||||
last = A.start;
|
last = A.start;
|
||||||
count = 1;
|
count = 1;
|
||||||
while (count < find) : ({last = index; count += 1}) {
|
while (count < find) : ({last = index; count += 1;}) {
|
||||||
index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count);
|
index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count);
|
||||||
if (index == A.end) break;
|
if (index == A.end) break;
|
||||||
}
|
}
|
||||||
@ -410,7 +410,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
|
|||||||
// these values will be pulled out to the end of B
|
// these values will be pulled out to the end of B
|
||||||
last = B.end - 1;
|
last = B.end - 1;
|
||||||
count = 1;
|
count = 1;
|
||||||
while (count < find) : ({last = index - 1; count += 1}) {
|
while (count < find) : ({last = index - 1; count += 1;}) {
|
||||||
index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count);
|
index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count);
|
||||||
if (index == B.start) break;
|
if (index == B.start) break;
|
||||||
}
|
}
|
||||||
@ -547,7 +547,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
|
|||||||
// swap the first value of each A block with the value in buffer1
|
// swap the first value of each A block with the value in buffer1
|
||||||
var indexA = buffer1.start;
|
var indexA = buffer1.start;
|
||||||
index = firstA.end;
|
index = firstA.end;
|
||||||
while (index < blockA.end) : ({indexA += 1; index += block_size}) {
|
while (index < blockA.end) : ({indexA += 1; index += block_size;}) {
|
||||||
mem.swap(T, &items[indexA], &items[index]);
|
mem.swap(T, &items[indexA], &items[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1093,7 +1093,7 @@ test "another sort case" {
|
|||||||
var arr = []i32{ 5, 3, 1, 2, 4 };
|
var arr = []i32{ 5, 3, 1, 2, 4 };
|
||||||
sort(i32, arr[0..], i32asc);
|
sort(i32, arr[0..], i32asc);
|
||||||
|
|
||||||
assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 }))
|
assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "sort fuzz testing" {
|
test "sort fuzz testing" {
|
||||||
|
@ -45,21 +45,17 @@ pub fn main() -> %void {
|
|||||||
|
|
||||||
var stderr_file = io.getStdErr();
|
var stderr_file = io.getStdErr();
|
||||||
var stderr_file_stream: io.FileOutStream = undefined;
|
var stderr_file_stream: io.FileOutStream = undefined;
|
||||||
var stderr_stream: %&io.OutStream = if (stderr_file) |*f| {
|
var stderr_stream: %&io.OutStream = if (stderr_file) |*f| x: {
|
||||||
stderr_file_stream = io.FileOutStream.init(f);
|
stderr_file_stream = io.FileOutStream.init(f);
|
||||||
&stderr_file_stream.stream
|
break :x &stderr_file_stream.stream;
|
||||||
} else |err| {
|
} else |err| err;
|
||||||
err
|
|
||||||
};
|
|
||||||
|
|
||||||
var stdout_file = io.getStdOut();
|
var stdout_file = io.getStdOut();
|
||||||
var stdout_file_stream: io.FileOutStream = undefined;
|
var stdout_file_stream: io.FileOutStream = undefined;
|
||||||
var stdout_stream: %&io.OutStream = if (stdout_file) |*f| {
|
var stdout_stream: %&io.OutStream = if (stdout_file) |*f| x: {
|
||||||
stdout_file_stream = io.FileOutStream.init(f);
|
stdout_file_stream = io.FileOutStream.init(f);
|
||||||
&stdout_file_stream.stream
|
break :x &stdout_file_stream.stream;
|
||||||
} else |err| {
|
} else |err| err;
|
||||||
err
|
|
||||||
};
|
|
||||||
|
|
||||||
while (arg_it.next(allocator)) |err_or_arg| {
|
while (arg_it.next(allocator)) |err_or_arg| {
|
||||||
const arg = %return unwrapArg(err_or_arg);
|
const arg = %return unwrapArg(err_or_arg);
|
||||||
|
@ -46,15 +46,15 @@ extern fn __stack_chk_fail() -> noreturn {
|
|||||||
|
|
||||||
const math = @import("../math/index.zig");
|
const math = @import("../math/index.zig");
|
||||||
|
|
||||||
export fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) }
|
export fn fmodf(x: f32, y: f32) -> f32 { return generic_fmod(f32, x, y); }
|
||||||
export fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) }
|
export fn fmod(x: f64, y: f64) -> f64 { return generic_fmod(f64, x, y); }
|
||||||
|
|
||||||
// TODO add intrinsics for these (and probably the double version too)
|
// TODO add intrinsics for these (and probably the double version too)
|
||||||
// and have the math stuff use the intrinsic. same as @mod and @rem
|
// and have the math stuff use the intrinsic. same as @mod and @rem
|
||||||
export fn floorf(x: f32) -> f32 { math.floor(x) }
|
export fn floorf(x: f32) -> f32 { return math.floor(x); }
|
||||||
export fn ceilf(x: f32) -> f32 { math.ceil(x) }
|
export fn ceilf(x: f32) -> f32 { return math.ceil(x); }
|
||||||
export fn floor(x: f64) -> f64 { math.floor(x) }
|
export fn floor(x: f64) -> f64 { return math.floor(x); }
|
||||||
export fn ceil(x: f64) -> f64 { math.ceil(x) }
|
export fn ceil(x: f64) -> f64 { return math.ceil(x); }
|
||||||
|
|
||||||
fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
||||||
@setDebugSafety(this, false);
|
@setDebugSafety(this, false);
|
||||||
@ -84,7 +84,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
|||||||
// normalize x and y
|
// normalize x and y
|
||||||
if (ex == 0) {
|
if (ex == 0) {
|
||||||
i = ux << exp_bits;
|
i = ux << exp_bits;
|
||||||
while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<= 1}) {}
|
while (i >> bits_minus_1 == 0) : (b: {ex -= 1; break :b i <<= 1;}) {}
|
||||||
ux <<= log2uint(@bitCast(u32, -ex + 1));
|
ux <<= log2uint(@bitCast(u32, -ex + 1));
|
||||||
} else {
|
} else {
|
||||||
ux &= @maxValue(uint) >> exp_bits;
|
ux &= @maxValue(uint) >> exp_bits;
|
||||||
@ -92,7 +92,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
|||||||
}
|
}
|
||||||
if (ey == 0) {
|
if (ey == 0) {
|
||||||
i = uy << exp_bits;
|
i = uy << exp_bits;
|
||||||
while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<= 1}) {}
|
while (i >> bits_minus_1 == 0) : (b: {ey -= 1; break :b i <<= 1;}) {}
|
||||||
uy <<= log2uint(@bitCast(u32, -ey + 1));
|
uy <<= log2uint(@bitCast(u32, -ey + 1));
|
||||||
} else {
|
} else {
|
||||||
uy &= @maxValue(uint) >> exp_bits;
|
uy &= @maxValue(uint) >> exp_bits;
|
||||||
@ -115,7 +115,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
|||||||
return 0 * x;
|
return 0 * x;
|
||||||
ux = i;
|
ux = i;
|
||||||
}
|
}
|
||||||
while (ux >> digits == 0) : ({ux <<= 1; ex -= 1}) {}
|
while (ux >> digits == 0) : (b: {ux <<= 1; break :b ex -= 1;}) {}
|
||||||
|
|
||||||
// scale result up
|
// scale result up
|
||||||
if (ex > 0) {
|
if (ex > 0) {
|
||||||
|
@ -38,27 +38,25 @@ pub extern fn __letf2(a: f128, b: f128) -> c_int {
|
|||||||
|
|
||||||
// If at least one of a and b is positive, we get the same result comparing
|
// If at least one of a and b is positive, we get the same result comparing
|
||||||
// a and b as signed integers as we would with a floating-point compare.
|
// a and b as signed integers as we would with a floating-point compare.
|
||||||
return if ((aInt & bInt) >= 0) {
|
return if ((aInt & bInt) >= 0)
|
||||||
if (aInt < bInt) {
|
if (aInt < bInt)
|
||||||
LE_LESS
|
LE_LESS
|
||||||
} else if (aInt == bInt) {
|
else if (aInt == bInt)
|
||||||
LE_EQUAL
|
LE_EQUAL
|
||||||
} else {
|
else
|
||||||
LE_GREATER
|
LE_GREATER
|
||||||
}
|
else
|
||||||
} else {
|
|
||||||
// Otherwise, both are negative, so we need to flip the sense of the
|
// Otherwise, both are negative, so we need to flip the sense of the
|
||||||
// comparison to get the correct result. (This assumes a twos- or ones-
|
// comparison to get the correct result. (This assumes a twos- or ones-
|
||||||
// complement integer representation; if integers are represented in a
|
// complement integer representation; if integers are represented in a
|
||||||
// sign-magnitude representation, then this flip is incorrect).
|
// sign-magnitude representation, then this flip is incorrect).
|
||||||
if (aInt > bInt) {
|
if (aInt > bInt)
|
||||||
LE_LESS
|
LE_LESS
|
||||||
} else if (aInt == bInt) {
|
else if (aInt == bInt)
|
||||||
LE_EQUAL
|
LE_EQUAL
|
||||||
} else {
|
else
|
||||||
LE_GREATER
|
LE_GREATER
|
||||||
}
|
;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO https://github.com/zig-lang/zig/issues/305
|
// TODO https://github.com/zig-lang/zig/issues/305
|
||||||
@ -78,23 +76,21 @@ pub extern fn __getf2(a: f128, b: f128) -> c_int {
|
|||||||
|
|
||||||
if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
|
if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
|
||||||
if ((aAbs | bAbs) == 0) return GE_EQUAL;
|
if ((aAbs | bAbs) == 0) return GE_EQUAL;
|
||||||
return if ((aInt & bInt) >= 0) {
|
return if ((aInt & bInt) >= 0)
|
||||||
if (aInt < bInt) {
|
if (aInt < bInt)
|
||||||
GE_LESS
|
GE_LESS
|
||||||
} else if (aInt == bInt) {
|
else if (aInt == bInt)
|
||||||
GE_EQUAL
|
GE_EQUAL
|
||||||
} else {
|
else
|
||||||
GE_GREATER
|
GE_GREATER
|
||||||
}
|
else
|
||||||
} else {
|
if (aInt > bInt)
|
||||||
if (aInt > bInt) {
|
|
||||||
GE_LESS
|
GE_LESS
|
||||||
} else if (aInt == bInt) {
|
else if (aInt == bInt)
|
||||||
GE_EQUAL
|
GE_EQUAL
|
||||||
} else {
|
else
|
||||||
GE_GREATER
|
GE_GREATER
|
||||||
}
|
;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern fn __unordtf2(a: f128, b: f128) -> c_int {
|
pub extern fn __unordtf2(a: f128, b: f128) -> c_int {
|
||||||
|
@ -10,7 +10,7 @@ test "global variable alignment" {
|
|||||||
assert(@typeOf(slice) == []align(4) u8);
|
assert(@typeOf(slice) == []align(4) u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derp() align(@sizeOf(usize) * 2) -> i32 { 1234 }
|
fn derp() align(@sizeOf(usize) * 2) -> i32 { return 1234; }
|
||||||
fn noop1() align(1) {}
|
fn noop1() align(1) {}
|
||||||
fn noop4() align(4) {}
|
fn noop4() align(4) {}
|
||||||
|
|
||||||
@ -53,14 +53,14 @@ test "implicitly decreasing pointer alignment" {
|
|||||||
assert(addUnaligned(&a, &b) == 7);
|
assert(addUnaligned(&a, &b) == 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) -> u32 { *a + *b }
|
fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) -> u32 { return *a + *b; }
|
||||||
|
|
||||||
test "implicitly decreasing slice alignment" {
|
test "implicitly decreasing slice alignment" {
|
||||||
const a: u32 align(4) = 3;
|
const a: u32 align(4) = 3;
|
||||||
const b: u32 align(8) = 4;
|
const b: u32 align(8) = 4;
|
||||||
assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7);
|
assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7);
|
||||||
}
|
}
|
||||||
fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) -> u32 { a[0] + b[0] }
|
fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) -> u32 { return a[0] + b[0]; }
|
||||||
|
|
||||||
test "specifying alignment allows pointer cast" {
|
test "specifying alignment allows pointer cast" {
|
||||||
testBytesAlign(0x33);
|
testBytesAlign(0x33);
|
||||||
@ -115,20 +115,20 @@ fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) -> i32, answer: i32) {
|
|||||||
assert(ptr() == answer);
|
assert(ptr() == answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alignedSmall() align(8) -> i32 { 1234 }
|
fn alignedSmall() align(8) -> i32 { return 1234; }
|
||||||
fn alignedBig() align(16) -> i32 { 5678 }
|
fn alignedBig() align(16) -> i32 { return 5678; }
|
||||||
|
|
||||||
|
|
||||||
test "@alignCast functions" {
|
test "@alignCast functions" {
|
||||||
assert(fnExpectsOnly1(simple4) == 0x19);
|
assert(fnExpectsOnly1(simple4) == 0x19);
|
||||||
}
|
}
|
||||||
fn fnExpectsOnly1(ptr: fn()align(1) -> i32) -> i32 {
|
fn fnExpectsOnly1(ptr: fn()align(1) -> i32) -> i32 {
|
||||||
fnExpects4(@alignCast(4, ptr))
|
return fnExpects4(@alignCast(4, ptr));
|
||||||
}
|
}
|
||||||
fn fnExpects4(ptr: fn()align(4) -> i32) -> i32 {
|
fn fnExpects4(ptr: fn()align(4) -> i32) -> i32 {
|
||||||
ptr()
|
return ptr();
|
||||||
}
|
}
|
||||||
fn simple4() align(4) -> i32 { 0x19 }
|
fn simple4() align(4) -> i32 { return 0x19; }
|
||||||
|
|
||||||
|
|
||||||
test "generic function with align param" {
|
test "generic function with align param" {
|
||||||
@ -137,7 +137,7 @@ test "generic function with align param" {
|
|||||||
assert(whyWouldYouEverDoThis(8) == 0x1);
|
assert(whyWouldYouEverDoThis(8) == 0x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) -> u8 { 0x1 }
|
fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) -> u8 { return 0x1; }
|
||||||
|
|
||||||
|
|
||||||
test "@ptrCast preserves alignment of bigger source" {
|
test "@ptrCast preserves alignment of bigger source" {
|
||||||
|
@ -22,7 +22,7 @@ test "arrays" {
|
|||||||
assert(getArrayLen(array) == 5);
|
assert(getArrayLen(array) == 5);
|
||||||
}
|
}
|
||||||
fn getArrayLen(a: []const u32) -> usize {
|
fn getArrayLen(a: []const u32) -> usize {
|
||||||
a.len
|
return a.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "void arrays" {
|
test "void arrays" {
|
||||||
@ -41,7 +41,7 @@ test "array literal" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "array dot len const expr" {
|
test "array dot len const expr" {
|
||||||
assert(comptime {some_array.len == 4});
|
assert(comptime x: {break :x some_array.len == 4;});
|
||||||
}
|
}
|
||||||
|
|
||||||
const ArrayDotLenConstExpr = struct {
|
const ArrayDotLenConstExpr = struct {
|
||||||
|
@ -10,5 +10,5 @@ fn testBitCast_i32_u32() {
|
|||||||
assert(conv2(@maxValue(u32)) == -1);
|
assert(conv2(@maxValue(u32)) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conv(x: i32) -> u32 { @bitCast(u32, x) }
|
fn conv(x: i32) -> u32 { return @bitCast(u32, x); }
|
||||||
fn conv2(x: u32) -> i32 { @bitCast(i32, x) }
|
fn conv2(x: u32) -> i32 { return @bitCast(i32, x); }
|
||||||
|
@ -22,7 +22,7 @@ test "bool cmp" {
|
|||||||
assert(testBoolCmp(true, false) == false);
|
assert(testBoolCmp(true, false) == false);
|
||||||
}
|
}
|
||||||
fn testBoolCmp(a: bool, b: bool) -> bool {
|
fn testBoolCmp(a: bool, b: bool) -> bool {
|
||||||
a == b
|
return a == b;
|
||||||
}
|
}
|
||||||
|
|
||||||
const global_f = false;
|
const global_f = false;
|
||||||
|
@ -50,7 +50,7 @@ test "peer resolve arrays of different size to const slice" {
|
|||||||
comptime assert(mem.eql(u8, boolToStr(false), "false"));
|
comptime assert(mem.eql(u8, boolToStr(false), "false"));
|
||||||
}
|
}
|
||||||
fn boolToStr(b: bool) -> []const u8 {
|
fn boolToStr(b: bool) -> []const u8 {
|
||||||
if (b) "true" else "false"
|
return if (b) "true" else "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -239,17 +239,17 @@ test "peer type resolution: error and [N]T" {
|
|||||||
|
|
||||||
error BadValue;
|
error BadValue;
|
||||||
fn testPeerErrorAndArray(x: u8) -> %[]const u8 {
|
fn testPeerErrorAndArray(x: u8) -> %[]const u8 {
|
||||||
switch (x) {
|
return switch (x) {
|
||||||
0x00 => "OK",
|
0x00 => "OK",
|
||||||
else => error.BadValue,
|
else => error.BadValue,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
fn testPeerErrorAndArray2(x: u8) -> %[]const u8 {
|
fn testPeerErrorAndArray2(x: u8) -> %[]const u8 {
|
||||||
switch (x) {
|
return switch (x) {
|
||||||
0x00 => "OK",
|
0x00 => "OK",
|
||||||
0x01 => "OKK",
|
0x01 => "OKK",
|
||||||
else => error.BadValue,
|
else => error.BadValue,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "explicit cast float number literal to integer if no fraction component" {
|
test "explicit cast float number literal to integer if no fraction component" {
|
||||||
@ -269,11 +269,11 @@ fn testCast128() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cast128Int(x: f128) -> u128 {
|
fn cast128Int(x: f128) -> u128 {
|
||||||
@bitCast(u128, x)
|
return @bitCast(u128, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cast128Float(x: u128) -> f128 {
|
fn cast128Float(x: u128) -> f128 {
|
||||||
@bitCast(f128, x)
|
return @bitCast(f128, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "const slice widen cast" {
|
test "const slice widen cast" {
|
||||||
|
@ -7,9 +7,9 @@ error FalseNotAllowed;
|
|||||||
|
|
||||||
fn runSomeErrorDefers(x: bool) -> %bool {
|
fn runSomeErrorDefers(x: bool) -> %bool {
|
||||||
index = 0;
|
index = 0;
|
||||||
defer {result[index] = 'a'; index += 1;};
|
defer {result[index] = 'a'; index += 1;}
|
||||||
%defer {result[index] = 'b'; index += 1;};
|
%defer {result[index] = 'b'; index += 1;}
|
||||||
defer {result[index] = 'c'; index += 1;};
|
defer {result[index] = 'c'; index += 1;}
|
||||||
return if (x) x else error.FalseNotAllowed;
|
return if (x) x else error.FalseNotAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,9 +18,9 @@ test "mixing normal and error defers" {
|
|||||||
assert(result[0] == 'c');
|
assert(result[0] == 'c');
|
||||||
assert(result[1] == 'a');
|
assert(result[1] == 'a');
|
||||||
|
|
||||||
const ok = runSomeErrorDefers(false) %% |err| {
|
const ok = runSomeErrorDefers(false) %% |err| x: {
|
||||||
assert(err == error.FalseNotAllowed);
|
assert(err == error.FalseNotAllowed);
|
||||||
true
|
break :x true;
|
||||||
};
|
};
|
||||||
assert(ok);
|
assert(ok);
|
||||||
assert(result[0] == 'c');
|
assert(result[0] == 'c');
|
||||||
@ -41,5 +41,5 @@ fn testBreakContInDefer(x: usize) {
|
|||||||
if (i == 5) break;
|
if (i == 5) break;
|
||||||
}
|
}
|
||||||
assert(i == 5);
|
assert(i == 5);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ const Bar = enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn returnAnInt(x: i32) -> Foo {
|
fn returnAnInt(x: i32) -> Foo {
|
||||||
Foo { .One = x }
|
return Foo { .One = x };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,9 +8,9 @@ const ET = union(enum) {
|
|||||||
|
|
||||||
pub fn print(a: &const ET, buf: []u8) -> %usize {
|
pub fn print(a: &const ET, buf: []u8) -> %usize {
|
||||||
return switch (*a) {
|
return switch (*a) {
|
||||||
ET.SINT => |x| { fmt.formatIntBuf(buf, x, 10, false, 0) },
|
ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
|
||||||
ET.UINT => |x| { fmt.formatIntBuf(buf, x, 10, false, 0) },
|
ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ const mem = @import("std").mem;
|
|||||||
|
|
||||||
pub fn foo() -> %i32 {
|
pub fn foo() -> %i32 {
|
||||||
const x = %return bar();
|
const x = %return bar();
|
||||||
return x + 1
|
return x + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bar() -> %i32 {
|
pub fn bar() -> %i32 {
|
||||||
@ -21,7 +21,7 @@ test "error wrapping" {
|
|||||||
|
|
||||||
error ItBroke;
|
error ItBroke;
|
||||||
fn gimmeItBroke() -> []const u8 {
|
fn gimmeItBroke() -> []const u8 {
|
||||||
@errorName(error.ItBroke)
|
return @errorName(error.ItBroke);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@errorName" {
|
test "@errorName" {
|
||||||
@ -48,7 +48,7 @@ error AnError;
|
|||||||
error AnError;
|
error AnError;
|
||||||
error SecondError;
|
error SecondError;
|
||||||
fn shouldBeNotEqual(a: error, b: error) {
|
fn shouldBeNotEqual(a: error, b: error) {
|
||||||
if (a == b) unreachable
|
if (a == b) unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -60,11 +60,7 @@ test "error binary operator" {
|
|||||||
}
|
}
|
||||||
error ItBroke;
|
error ItBroke;
|
||||||
fn errBinaryOperatorG(x: bool) -> %isize {
|
fn errBinaryOperatorG(x: bool) -> %isize {
|
||||||
if (x) {
|
return if (x) error.ItBroke else isize(10);
|
||||||
error.ItBroke
|
|
||||||
} else {
|
|
||||||
isize(10)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -72,7 +68,7 @@ test "unwrap simple value from error" {
|
|||||||
const i = %%unwrapSimpleValueFromErrorDo();
|
const i = %%unwrapSimpleValueFromErrorDo();
|
||||||
assert(i == 13);
|
assert(i == 13);
|
||||||
}
|
}
|
||||||
fn unwrapSimpleValueFromErrorDo() -> %isize { 13 }
|
fn unwrapSimpleValueFromErrorDo() -> %isize { return 13; }
|
||||||
|
|
||||||
|
|
||||||
test "error return in assignment" {
|
test "error return in assignment" {
|
||||||
|
@ -44,7 +44,7 @@ test "static function evaluation" {
|
|||||||
assert(statically_added_number == 3);
|
assert(statically_added_number == 3);
|
||||||
}
|
}
|
||||||
const statically_added_number = staticAdd(1, 2);
|
const statically_added_number = staticAdd(1, 2);
|
||||||
fn staticAdd(a: i32, b: i32) -> i32 { a + b }
|
fn staticAdd(a: i32, b: i32) -> i32 { return a + b; }
|
||||||
|
|
||||||
|
|
||||||
test "const expr eval on single expr blocks" {
|
test "const expr eval on single expr blocks" {
|
||||||
@ -54,10 +54,10 @@ test "const expr eval on single expr blocks" {
|
|||||||
fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) -> i32 {
|
fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) -> i32 {
|
||||||
const literal = 3;
|
const literal = 3;
|
||||||
|
|
||||||
const result = if (b) {
|
const result = if (b) b: {
|
||||||
literal
|
break :b literal;
|
||||||
} else {
|
} else b: {
|
||||||
x
|
break :b x;
|
||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -94,9 +94,9 @@ pub const Vec3 = struct {
|
|||||||
data: [3]f32,
|
data: [3]f32,
|
||||||
};
|
};
|
||||||
pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 {
|
pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 {
|
||||||
Vec3 {
|
return Vec3 {
|
||||||
.data = []f32 { x, y, z, },
|
.data = []f32 { x, y, z, },
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ fn max(comptime T: type, a: T, b: T) -> T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn letsTryToCompareBools(a: bool, b: bool) -> bool {
|
fn letsTryToCompareBools(a: bool, b: bool) -> bool {
|
||||||
max(bool, a, b)
|
return max(bool, a, b);
|
||||||
}
|
}
|
||||||
test "inlined block and runtime block phi" {
|
test "inlined block and runtime block phi" {
|
||||||
assert(letsTryToCompareBools(true, true));
|
assert(letsTryToCompareBools(true, true));
|
||||||
@ -202,9 +202,9 @@ const cmd_fns = []CmdFn{
|
|||||||
CmdFn {.name = "two", .func = two},
|
CmdFn {.name = "two", .func = two},
|
||||||
CmdFn {.name = "three", .func = three},
|
CmdFn {.name = "three", .func = three},
|
||||||
};
|
};
|
||||||
fn one(value: i32) -> i32 { value + 1 }
|
fn one(value: i32) -> i32 { return value + 1; }
|
||||||
fn two(value: i32) -> i32 { value + 2 }
|
fn two(value: i32) -> i32 { return value + 2; }
|
||||||
fn three(value: i32) -> i32 { value + 3 }
|
fn three(value: i32) -> i32 { return value + 3; }
|
||||||
|
|
||||||
fn performFn(comptime prefix_char: u8, start_value: i32) -> i32 {
|
fn performFn(comptime prefix_char: u8, start_value: i32) -> i32 {
|
||||||
var result: i32 = start_value;
|
var result: i32 = start_value;
|
||||||
@ -317,12 +317,12 @@ test "create global array with for loop" {
|
|||||||
assert(global_array[9] == 9 * 9);
|
assert(global_array[9] == 9 * 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
const global_array = {
|
const global_array = x: {
|
||||||
var result: [10]usize = undefined;
|
var result: [10]usize = undefined;
|
||||||
for (result) |*item, index| {
|
for (result) |*item, index| {
|
||||||
*item = index * index;
|
*item = index * index;
|
||||||
}
|
}
|
||||||
result
|
break :x result;
|
||||||
};
|
};
|
||||||
|
|
||||||
test "compile-time downcast when the bits fit" {
|
test "compile-time downcast when the bits fit" {
|
||||||
|
@ -4,7 +4,7 @@ test "params" {
|
|||||||
assert(testParamsAdd(22, 11) == 33);
|
assert(testParamsAdd(22, 11) == 33);
|
||||||
}
|
}
|
||||||
fn testParamsAdd(a: i32, b: i32) -> i32 {
|
fn testParamsAdd(a: i32, b: i32) -> i32 {
|
||||||
a + b
|
return a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ test "void parameters" {
|
|||||||
}
|
}
|
||||||
fn voidFun(a: i32, b: void, c: i32, d: void) {
|
fn voidFun(a: i32, b: void, c: i32, d: void) {
|
||||||
const v = b;
|
const v = b;
|
||||||
const vv: void = if (a == 1) {v} else {};
|
const vv: void = if (a == 1) v else {};
|
||||||
assert(a + c == 3);
|
assert(a + c == 3);
|
||||||
return vv;
|
return vv;
|
||||||
}
|
}
|
||||||
@ -45,9 +45,9 @@ test "separate block scopes" {
|
|||||||
assert(no_conflict == 5);
|
assert(no_conflict == 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
const c = {
|
const c = x: {
|
||||||
const no_conflict = i32(10);
|
const no_conflict = i32(10);
|
||||||
no_conflict
|
break :x no_conflict;
|
||||||
};
|
};
|
||||||
assert(c == 10);
|
assert(c == 10);
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ test "implicit cast function unreachable return" {
|
|||||||
fn wantsFnWithVoid(f: fn()) { }
|
fn wantsFnWithVoid(f: fn()) { }
|
||||||
|
|
||||||
fn fnWithUnreachable() -> noreturn {
|
fn fnWithUnreachable() -> noreturn {
|
||||||
unreachable
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -83,14 +83,14 @@ test "function pointers" {
|
|||||||
assert(f() == u32(i) + 5);
|
assert(f() == u32(i) + 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fn1() -> u32 {5}
|
fn fn1() -> u32 {return 5;}
|
||||||
fn fn2() -> u32 {6}
|
fn fn2() -> u32 {return 6;}
|
||||||
fn fn3() -> u32 {7}
|
fn fn3() -> u32 {return 7;}
|
||||||
fn fn4() -> u32 {8}
|
fn fn4() -> u32 {return 8;}
|
||||||
|
|
||||||
|
|
||||||
test "inline function call" {
|
test "inline function call" {
|
||||||
assert(@inlineCall(add, 3, 9) == 12);
|
assert(@inlineCall(add, 3, 9) == 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(a: i32, b: i32) -> i32 { a + b }
|
fn add(a: i32, b: i32) -> i32 { return a + b; }
|
||||||
|
@ -12,7 +12,7 @@ test "continue in for loop" {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (sum != 6) unreachable
|
if (sum != 6) unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "for loop with pointer elem var" {
|
test "for loop with pointer elem var" {
|
||||||
|
@ -11,7 +11,7 @@ fn max(comptime T: type, a: T, b: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add(comptime a: i32, b: i32) -> i32 {
|
fn add(comptime a: i32, b: i32) -> i32 {
|
||||||
return (comptime {a}) + b;
|
return (comptime a) + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
const the_max = max(u32, 1234, 5678);
|
const the_max = max(u32, 1234, 5678);
|
||||||
@ -20,15 +20,15 @@ test "compile time generic eval" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn gimmeTheBigOne(a: u32, b: u32) -> u32 {
|
fn gimmeTheBigOne(a: u32, b: u32) -> u32 {
|
||||||
max(u32, a, b)
|
return max(u32, a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shouldCallSameInstance(a: u32, b: u32) -> u32 {
|
fn shouldCallSameInstance(a: u32, b: u32) -> u32 {
|
||||||
max(u32, a, b)
|
return max(u32, a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sameButWithFloats(a: f64, b: f64) -> f64 {
|
fn sameButWithFloats(a: f64, b: f64) -> f64 {
|
||||||
max(f64, a, b)
|
return max(f64, a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fn with comptime args" {
|
test "fn with comptime args" {
|
||||||
@ -49,28 +49,28 @@ comptime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn max_var(a: var, b: var) -> @typeOf(a + b) {
|
fn max_var(a: var, b: var) -> @typeOf(a + b) {
|
||||||
if (a > b) a else b
|
return if (a > b) a else b;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_i32(a: i32, b: i32) -> i32 {
|
fn max_i32(a: i32, b: i32) -> i32 {
|
||||||
max_var(a, b)
|
return max_var(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_f64(a: f64, b: f64) -> f64 {
|
fn max_f64(a: f64, b: f64) -> f64 {
|
||||||
max_var(a, b)
|
return max_var(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn List(comptime T: type) -> type {
|
pub fn List(comptime T: type) -> type {
|
||||||
SmallList(T, 8)
|
return SmallList(T, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
|
pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
|
||||||
struct {
|
return struct {
|
||||||
items: []T,
|
items: []T,
|
||||||
length: usize,
|
length: usize,
|
||||||
prealloc_items: [STATIC_SIZE]T,
|
prealloc_items: [STATIC_SIZE]T,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "function with return type type" {
|
test "function with return type type" {
|
||||||
@ -91,20 +91,20 @@ test "generic struct" {
|
|||||||
assert(b1.getVal());
|
assert(b1.getVal());
|
||||||
}
|
}
|
||||||
fn GenNode(comptime T: type) -> type {
|
fn GenNode(comptime T: type) -> type {
|
||||||
struct {
|
return struct {
|
||||||
value: T,
|
value: T,
|
||||||
next: ?&GenNode(T),
|
next: ?&GenNode(T),
|
||||||
fn getVal(n: &const GenNode(T)) -> T { n.value }
|
fn getVal(n: &const GenNode(T)) -> T { return n.value; }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "const decls in struct" {
|
test "const decls in struct" {
|
||||||
assert(GenericDataThing(3).count_plus_one == 4);
|
assert(GenericDataThing(3).count_plus_one == 4);
|
||||||
}
|
}
|
||||||
fn GenericDataThing(comptime count: isize) -> type {
|
fn GenericDataThing(comptime count: isize) -> type {
|
||||||
struct {
|
return struct {
|
||||||
const count_plus_one = count + 1;
|
const count_plus_one = count + 1;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -120,16 +120,16 @@ test "generic fn with implicit cast" {
|
|||||||
assert(getFirstByte(u8, []u8 {13}) == 13);
|
assert(getFirstByte(u8, []u8 {13}) == 13);
|
||||||
assert(getFirstByte(u16, []u16 {0, 13}) == 0);
|
assert(getFirstByte(u16, []u16 {0, 13}) == 0);
|
||||||
}
|
}
|
||||||
fn getByte(ptr: ?&const u8) -> u8 {*??ptr}
|
fn getByte(ptr: ?&const u8) -> u8 {return *??ptr;}
|
||||||
fn getFirstByte(comptime T: type, mem: []const T) -> u8 {
|
fn getFirstByte(comptime T: type, mem: []const T) -> u8 {
|
||||||
getByte(@ptrCast(&const u8, &mem[0]))
|
return getByte(@ptrCast(&const u8, &mem[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const foos = []fn(var) -> bool { foo1, foo2 };
|
const foos = []fn(var) -> bool { foo1, foo2 };
|
||||||
|
|
||||||
fn foo1(arg: var) -> bool { arg }
|
fn foo1(arg: var) -> bool { return arg; }
|
||||||
fn foo2(arg: var) -> bool { !arg }
|
fn foo2(arg: var) -> bool { return !arg; }
|
||||||
|
|
||||||
test "array of generic fns" {
|
test "array of generic fns" {
|
||||||
assert(foos[0](true));
|
assert(foos[0](true));
|
||||||
|
@ -29,10 +29,10 @@ test "else if expression" {
|
|||||||
}
|
}
|
||||||
fn elseIfExpressionF(c: u8) -> u8 {
|
fn elseIfExpressionF(c: u8) -> u8 {
|
||||||
if (c == 0) {
|
if (c == 0) {
|
||||||
0
|
return 0;
|
||||||
} else if (c == 1) {
|
} else if (c == 1) {
|
||||||
1
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
u8(2)
|
return u8(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
pub fn foo() -> i32 { 1234 }
|
pub fn foo() -> i32 { return 1234; }
|
||||||
|
@ -8,10 +8,10 @@ fn foo(id: u64) -> %i32 {
|
|||||||
return %return getErrInt();
|
return %return getErrInt();
|
||||||
},
|
},
|
||||||
else => error.ItBroke,
|
else => error.ItBroke,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getErrInt() -> %i32 { 0 }
|
fn getErrInt() -> %i32 { return 0; }
|
||||||
|
|
||||||
error ItBroke;
|
error ItBroke;
|
||||||
|
|
||||||
|
@ -28,16 +28,16 @@ fn testDivision() {
|
|||||||
assert(divTrunc(f32, -5.0, 3.0) == -1.0);
|
assert(divTrunc(f32, -5.0, 3.0) == -1.0);
|
||||||
}
|
}
|
||||||
fn div(comptime T: type, a: T, b: T) -> T {
|
fn div(comptime T: type, a: T, b: T) -> T {
|
||||||
a / b
|
return a / b;
|
||||||
}
|
}
|
||||||
fn divExact(comptime T: type, a: T, b: T) -> T {
|
fn divExact(comptime T: type, a: T, b: T) -> T {
|
||||||
@divExact(a, b)
|
return @divExact(a, b);
|
||||||
}
|
}
|
||||||
fn divFloor(comptime T: type, a: T, b: T) -> T {
|
fn divFloor(comptime T: type, a: T, b: T) -> T {
|
||||||
@divFloor(a, b)
|
return @divFloor(a, b);
|
||||||
}
|
}
|
||||||
fn divTrunc(comptime T: type, a: T, b: T) -> T {
|
fn divTrunc(comptime T: type, a: T, b: T) -> T {
|
||||||
@divTrunc(a, b)
|
return @divTrunc(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@addWithOverflow" {
|
test "@addWithOverflow" {
|
||||||
@ -71,7 +71,7 @@ fn testClz() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn clz(x: var) -> usize {
|
fn clz(x: var) -> usize {
|
||||||
@clz(x)
|
return @clz(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@ctz" {
|
test "@ctz" {
|
||||||
@ -86,7 +86,7 @@ fn testCtz() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ctz(x: var) -> usize {
|
fn ctz(x: var) -> usize {
|
||||||
@ctz(x)
|
return @ctz(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "assignment operators" {
|
test "assignment operators" {
|
||||||
@ -180,10 +180,10 @@ fn test_u64_div() {
|
|||||||
assert(result.remainder == 100663296);
|
assert(result.remainder == 100663296);
|
||||||
}
|
}
|
||||||
fn divWithResult(a: u64, b: u64) -> DivResult {
|
fn divWithResult(a: u64, b: u64) -> DivResult {
|
||||||
DivResult {
|
return DivResult {
|
||||||
.quotient = a / b,
|
.quotient = a / b,
|
||||||
.remainder = a % b,
|
.remainder = a % b,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
const DivResult = struct {
|
const DivResult = struct {
|
||||||
quotient: u64,
|
quotient: u64,
|
||||||
@ -191,8 +191,8 @@ const DivResult = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test "binary not" {
|
test "binary not" {
|
||||||
assert(comptime {~u16(0b1010101010101010) == 0b0101010101010101});
|
assert(comptime x: {break :x ~u16(0b1010101010101010) == 0b0101010101010101;});
|
||||||
assert(comptime {~u64(2147483647) == 18446744071562067968});
|
assert(comptime x: {break :x ~u64(2147483647) == 18446744071562067968;});
|
||||||
testBinaryNot(0b1010101010101010);
|
testBinaryNot(0b1010101010101010);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,7 +331,7 @@ test "f128" {
|
|||||||
comptime test_f128();
|
comptime test_f128();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_f128(x: f128) -> f128 { x }
|
fn make_f128(x: f128) -> f128 { return x; }
|
||||||
|
|
||||||
fn test_f128() {
|
fn test_f128() {
|
||||||
assert(@sizeOf(f128) == 16);
|
assert(@sizeOf(f128) == 16);
|
||||||
|
@ -110,17 +110,17 @@ fn testShortCircuit(f: bool, t: bool) {
|
|||||||
var hit_3 = f;
|
var hit_3 = f;
|
||||||
var hit_4 = f;
|
var hit_4 = f;
|
||||||
|
|
||||||
if (t or {assert(f); f}) {
|
if (t or x: {assert(f); break :x f;}) {
|
||||||
hit_1 = t;
|
hit_1 = t;
|
||||||
}
|
}
|
||||||
if (f or { hit_2 = t; f }) {
|
if (f or x: { hit_2 = t; break :x f; }) {
|
||||||
assert(f);
|
assert(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t and { hit_3 = t; f }) {
|
if (t and x: { hit_3 = t; break :x f; }) {
|
||||||
assert(f);
|
assert(f);
|
||||||
}
|
}
|
||||||
if (f and {assert(f); f}) {
|
if (f and x: {assert(f); break :x f;}) {
|
||||||
assert(f);
|
assert(f);
|
||||||
} else {
|
} else {
|
||||||
hit_4 = t;
|
hit_4 = t;
|
||||||
@ -135,11 +135,11 @@ test "truncate" {
|
|||||||
assert(testTruncate(0x10fd) == 0xfd);
|
assert(testTruncate(0x10fd) == 0xfd);
|
||||||
}
|
}
|
||||||
fn testTruncate(x: u32) -> u8 {
|
fn testTruncate(x: u32) -> u8 {
|
||||||
@truncate(u8, x)
|
return @truncate(u8, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first4KeysOfHomeRow() -> []const u8 {
|
fn first4KeysOfHomeRow() -> []const u8 {
|
||||||
"aoeu"
|
return "aoeu";
|
||||||
}
|
}
|
||||||
|
|
||||||
test "return string from function" {
|
test "return string from function" {
|
||||||
@ -167,7 +167,7 @@ test "memcpy and memset intrinsics" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "builtin static eval" {
|
test "builtin static eval" {
|
||||||
const x : i32 = comptime {1 + 2 + 3};
|
const x : i32 = comptime x: {break :x 1 + 2 + 3;};
|
||||||
assert(x == comptime 6);
|
assert(x == comptime 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ test "slicing" {
|
|||||||
|
|
||||||
test "constant equal function pointers" {
|
test "constant equal function pointers" {
|
||||||
const alias = emptyFn;
|
const alias = emptyFn;
|
||||||
assert(comptime {emptyFn == alias});
|
assert(comptime x: {break :x emptyFn == alias;});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emptyFn() {}
|
fn emptyFn() {}
|
||||||
@ -280,14 +280,14 @@ test "cast small unsigned to larger signed" {
|
|||||||
assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
|
assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
|
||||||
assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
|
assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
|
||||||
}
|
}
|
||||||
fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { x }
|
fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { return x; }
|
||||||
fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { x }
|
fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { return x; }
|
||||||
|
|
||||||
|
|
||||||
test "implicit cast after unreachable" {
|
test "implicit cast after unreachable" {
|
||||||
assert(outer() == 1234);
|
assert(outer() == 1234);
|
||||||
}
|
}
|
||||||
fn inner() -> i32 { 1234 }
|
fn inner() -> i32 { return 1234; }
|
||||||
fn outer() -> i64 {
|
fn outer() -> i64 {
|
||||||
return inner();
|
return inner();
|
||||||
}
|
}
|
||||||
@ -310,8 +310,8 @@ test "call result of if else expression" {
|
|||||||
fn f2(x: bool) -> []const u8 {
|
fn f2(x: bool) -> []const u8 {
|
||||||
return (if (x) fA else fB)();
|
return (if (x) fA else fB)();
|
||||||
}
|
}
|
||||||
fn fA() -> []const u8 { "a" }
|
fn fA() -> []const u8 { return "a"; }
|
||||||
fn fB() -> []const u8 { "b" }
|
fn fB() -> []const u8 { return "b"; }
|
||||||
|
|
||||||
|
|
||||||
test "const expression eval handling of variables" {
|
test "const expression eval handling of variables" {
|
||||||
@ -379,7 +379,7 @@ test "pointer comparison" {
|
|||||||
assert(ptrEql(b, b));
|
assert(ptrEql(b, b));
|
||||||
}
|
}
|
||||||
fn ptrEql(a: &const []const u8, b: &const []const u8) -> bool {
|
fn ptrEql(a: &const []const u8, b: &const []const u8) -> bool {
|
||||||
a == b
|
return a == b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -483,7 +483,7 @@ test "@typeId" {
|
|||||||
assert(@typeId(AUnion) == Tid.Union);
|
assert(@typeId(AUnion) == Tid.Union);
|
||||||
assert(@typeId(fn()) == Tid.Fn);
|
assert(@typeId(fn()) == Tid.Fn);
|
||||||
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
|
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
|
||||||
assert(@typeId(@typeOf({this})) == Tid.Block);
|
assert(@typeId(@typeOf(x: {break :x this;})) == Tid.Block);
|
||||||
// TODO bound fn
|
// TODO bound fn
|
||||||
// TODO arg tuple
|
// TODO arg tuple
|
||||||
// TODO opaque
|
// TODO opaque
|
||||||
|
@ -22,7 +22,7 @@ test "reflection: function return type, var args, and param types" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }
|
fn dummy(a: bool, b: i32, c: f32) -> i32 { return 1234; }
|
||||||
fn dummy_varargs(args: ...) {}
|
fn dummy_varargs(args: ...) {}
|
||||||
|
|
||||||
test "reflection: struct member types and names" {
|
test "reflection: struct member types and names" {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user