[breaking] delete ptr deref prefix op
start using zig-fmt-pointer-reform branch build of zig fmt to fix code to use the new syntax all of test/cases/* are processed, but there are more left to be done - all the std lib used by the behavior tests
This commit is contained in:
parent
76ab1d2b6c
commit
a35b366eb6
@ -614,7 +614,6 @@ enum PrefixOp {
|
|||||||
PrefixOpBinNot,
|
PrefixOpBinNot,
|
||||||
PrefixOpNegation,
|
PrefixOpNegation,
|
||||||
PrefixOpNegationWrap,
|
PrefixOpNegationWrap,
|
||||||
PrefixOpDereference,
|
|
||||||
PrefixOpMaybe,
|
PrefixOpMaybe,
|
||||||
PrefixOpUnwrapMaybe,
|
PrefixOpUnwrapMaybe,
|
||||||
};
|
};
|
||||||
|
@ -66,7 +66,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
|
|||||||
case PrefixOpNegationWrap: return "-%";
|
case PrefixOpNegationWrap: return "-%";
|
||||||
case PrefixOpBoolNot: return "!";
|
case PrefixOpBoolNot: return "!";
|
||||||
case PrefixOpBinNot: return "~";
|
case PrefixOpBinNot: return "~";
|
||||||
case PrefixOpDereference: return "*";
|
|
||||||
case PrefixOpMaybe: return "?";
|
case PrefixOpMaybe: return "?";
|
||||||
case PrefixOpUnwrapMaybe: return "??";
|
case PrefixOpUnwrapMaybe: return "??";
|
||||||
}
|
}
|
||||||
|
@ -4696,8 +4696,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
|
|||||||
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
|
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
|
||||||
case PrefixOpNegationWrap:
|
case PrefixOpNegationWrap:
|
||||||
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
|
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
|
||||||
case PrefixOpDereference:
|
|
||||||
return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
|
|
||||||
case PrefixOpMaybe:
|
case PrefixOpMaybe:
|
||||||
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);
|
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);
|
||||||
case PrefixOpUnwrapMaybe:
|
case PrefixOpUnwrapMaybe:
|
||||||
|
@ -1165,10 +1165,8 @@ static PrefixOp tok_to_prefix_op(Token *token) {
|
|||||||
case TokenIdDash: return PrefixOpNegation;
|
case TokenIdDash: return PrefixOpNegation;
|
||||||
case TokenIdMinusPercent: return PrefixOpNegationWrap;
|
case TokenIdMinusPercent: return PrefixOpNegationWrap;
|
||||||
case TokenIdTilde: return PrefixOpBinNot;
|
case TokenIdTilde: return PrefixOpBinNot;
|
||||||
case TokenIdStar: return PrefixOpDereference;
|
|
||||||
case TokenIdMaybe: return PrefixOpMaybe;
|
case TokenIdMaybe: return PrefixOpMaybe;
|
||||||
case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
|
case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
|
||||||
case TokenIdStarStar: return PrefixOpDereference;
|
|
||||||
default: return PrefixOpInvalid;
|
default: return PrefixOpInvalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1214,7 +1212,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
|
PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
|
||||||
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
|
PrefixOp = "!" | "-" | "~" | ("*" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
Token *token = &pc->tokens->at(*token_index);
|
||||||
@ -1237,15 +1235,6 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
|
|||||||
|
|
||||||
AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
|
AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
|
||||||
AstNode *parent_node = node;
|
AstNode *parent_node = node;
|
||||||
if (token->id == TokenIdStarStar) {
|
|
||||||
// pretend that we got 2 star tokens
|
|
||||||
|
|
||||||
parent_node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
|
|
||||||
parent_node->data.prefix_op_expr.primary_expr = node;
|
|
||||||
parent_node->data.prefix_op_expr.prefix_op = PrefixOpDereference;
|
|
||||||
|
|
||||||
node->column += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
AstNode *prefix_op_expr = ast_parse_error_set_expr(pc, token_index, true);
|
AstNode *prefix_op_expr = ast_parse_error_set_expr(pc, token_index, true);
|
||||||
node->data.prefix_op_expr.primary_expr = prefix_op_expr;
|
node->data.prefix_op_expr.primary_expr = prefix_op_expr;
|
||||||
|
@ -247,6 +247,12 @@ static AstNode *trans_create_node_field_access_str(Context *c, AstNode *containe
|
|||||||
return trans_create_node_field_access(c, container, buf_create_from_str(field_name));
|
return trans_create_node_field_access(c, container, buf_create_from_str(field_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AstNode *trans_create_node_ptr_deref(Context *c, AstNode *child_node) {
|
||||||
|
AstNode *node = trans_create_node(c, NodeTypePtrDeref);
|
||||||
|
node->data.ptr_deref_expr.target = child_node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) {
|
static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) {
|
||||||
AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);
|
AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);
|
||||||
node->data.prefix_op_expr.prefix_op = op;
|
node->data.prefix_op_expr.prefix_op = op;
|
||||||
@ -1412,8 +1418,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
|
|||||||
AstNode *operation_type_cast = trans_c_cast(c, rhs_location,
|
AstNode *operation_type_cast = trans_c_cast(c, rhs_location,
|
||||||
stmt->getComputationLHSType(),
|
stmt->getComputationLHSType(),
|
||||||
stmt->getLHS()->getType(),
|
stmt->getLHS()->getType(),
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_ptr_deref(c, trans_create_node_symbol(c, tmp_var_name)));
|
||||||
trans_create_node_symbol(c, tmp_var_name)));
|
|
||||||
|
|
||||||
// result_type(... >> u5(rhs))
|
// result_type(... >> u5(rhs))
|
||||||
AstNode *result_type_cast = trans_c_cast(c, rhs_location,
|
AstNode *result_type_cast = trans_c_cast(c, rhs_location,
|
||||||
@ -1426,7 +1431,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
|
|||||||
|
|
||||||
// *_ref = ...
|
// *_ref = ...
|
||||||
AstNode *assign_statement = trans_create_node_bin_op(c,
|
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_ptr_deref(c,
|
||||||
trans_create_node_symbol(c, tmp_var_name)),
|
trans_create_node_symbol(c, tmp_var_name)),
|
||||||
BinOpTypeAssign, result_type_cast);
|
BinOpTypeAssign, result_type_cast);
|
||||||
|
|
||||||
@ -1436,7 +1441,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
|
|||||||
// break :x *_ref
|
// break :x *_ref
|
||||||
child_scope->node->data.block.statements.append(
|
child_scope->node->data.block.statements.append(
|
||||||
trans_create_node_break(c, label_name,
|
trans_create_node_break(c, label_name,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_ptr_deref(c,
|
||||||
trans_create_node_symbol(c, tmp_var_name))));
|
trans_create_node_symbol(c, tmp_var_name))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1483,11 +1488,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
|
|||||||
if (rhs == nullptr) return nullptr;
|
if (rhs == nullptr) return nullptr;
|
||||||
|
|
||||||
AstNode *assign_statement = trans_create_node_bin_op(c,
|
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_ptr_deref(c,
|
||||||
trans_create_node_symbol(c, tmp_var_name)),
|
trans_create_node_symbol(c, tmp_var_name)),
|
||||||
BinOpTypeAssign,
|
BinOpTypeAssign,
|
||||||
trans_create_node_bin_op(c,
|
trans_create_node_bin_op(c,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_ptr_deref(c,
|
||||||
trans_create_node_symbol(c, tmp_var_name)),
|
trans_create_node_symbol(c, tmp_var_name)),
|
||||||
bin_op,
|
bin_op,
|
||||||
rhs));
|
rhs));
|
||||||
@ -1496,7 +1501,7 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
|
|||||||
// break :x *_ref
|
// break :x *_ref
|
||||||
child_scope->node->data.block.statements.append(
|
child_scope->node->data.block.statements.append(
|
||||||
trans_create_node_break(c, label_name,
|
trans_create_node_break(c, label_name,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_ptr_deref(c,
|
||||||
trans_create_node_symbol(c, tmp_var_name))));
|
trans_create_node_symbol(c, tmp_var_name))));
|
||||||
|
|
||||||
return child_scope->node;
|
return child_scope->node;
|
||||||
@ -1817,13 +1822,13 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
|
|||||||
// const _tmp = *_ref;
|
// const _tmp = *_ref;
|
||||||
Buf* tmp_var_name = buf_create_from_str("_tmp");
|
Buf* tmp_var_name = buf_create_from_str("_tmp");
|
||||||
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
|
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_ptr_deref(c,
|
||||||
trans_create_node_symbol(c, ref_var_name)));
|
trans_create_node_symbol(c, ref_var_name)));
|
||||||
child_scope->node->data.block.statements.append(tmp_var_decl);
|
child_scope->node->data.block.statements.append(tmp_var_decl);
|
||||||
|
|
||||||
// *_ref += 1;
|
// *_ref += 1;
|
||||||
AstNode *assign_statement = trans_create_node_bin_op(c,
|
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_ptr_deref(c,
|
||||||
trans_create_node_symbol(c, ref_var_name)),
|
trans_create_node_symbol(c, ref_var_name)),
|
||||||
assign_op,
|
assign_op,
|
||||||
trans_create_node_unsigned(c, 1));
|
trans_create_node_unsigned(c, 1));
|
||||||
@ -1871,14 +1876,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
|
|||||||
|
|
||||||
// *_ref += 1;
|
// *_ref += 1;
|
||||||
AstNode *assign_statement = trans_create_node_bin_op(c,
|
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_ptr_deref(c,
|
||||||
trans_create_node_symbol(c, ref_var_name)),
|
trans_create_node_symbol(c, ref_var_name)),
|
||||||
assign_op,
|
assign_op,
|
||||||
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);
|
||||||
|
|
||||||
// break :x *_ref
|
// break :x *_ref
|
||||||
AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
|
AstNode *deref_expr = trans_create_node_ptr_deref(c,
|
||||||
trans_create_node_symbol(c, ref_var_name));
|
trans_create_node_symbol(c, ref_var_name));
|
||||||
child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));
|
child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));
|
||||||
|
|
||||||
@ -1923,7 +1928,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
|
|||||||
if (is_fn_ptr)
|
if (is_fn_ptr)
|
||||||
return value_node;
|
return value_node;
|
||||||
AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
|
AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
|
||||||
return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped);
|
return trans_create_node_ptr_deref(c, unwrapped);
|
||||||
}
|
}
|
||||||
case UO_Plus:
|
case UO_Plus:
|
||||||
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus");
|
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus");
|
||||||
@ -4469,27 +4474,45 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PrefixOp ctok_to_prefix_op(CTok *token) {
|
|
||||||
switch (token->id) {
|
|
||||||
case CTokIdBang: return PrefixOpBoolNot;
|
|
||||||
case CTokIdMinus: return PrefixOpNegation;
|
|
||||||
case CTokIdTilde: return PrefixOpBinNot;
|
|
||||||
case CTokIdAsterisk: return PrefixOpDereference;
|
|
||||||
default: return PrefixOpInvalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) {
|
static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) {
|
||||||
CTok *op_tok = &ctok->tokens.at(*tok_i);
|
CTok *op_tok = &ctok->tokens.at(*tok_i);
|
||||||
PrefixOp prefix_op = ctok_to_prefix_op(op_tok);
|
|
||||||
if (prefix_op == PrefixOpInvalid) {
|
|
||||||
return parse_ctok_suffix_op_expr(c, ctok, tok_i);
|
|
||||||
}
|
|
||||||
*tok_i += 1;
|
|
||||||
|
|
||||||
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
switch (op_tok->id) {
|
||||||
if (prefix_op_expr == nullptr)
|
case CTokIdBang:
|
||||||
return nullptr;
|
{
|
||||||
return trans_create_node_prefix_op(c, prefix_op, prefix_op_expr);
|
*tok_i += 1;
|
||||||
|
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
||||||
|
if (prefix_op_expr == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
return trans_create_node_prefix_op(c, PrefixOpBoolNot, prefix_op_expr);
|
||||||
|
}
|
||||||
|
case CTokIdMinus:
|
||||||
|
{
|
||||||
|
*tok_i += 1;
|
||||||
|
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
||||||
|
if (prefix_op_expr == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
return trans_create_node_prefix_op(c, PrefixOpNegation, prefix_op_expr);
|
||||||
|
}
|
||||||
|
case CTokIdTilde:
|
||||||
|
{
|
||||||
|
*tok_i += 1;
|
||||||
|
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
||||||
|
if (prefix_op_expr == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
return trans_create_node_prefix_op(c, PrefixOpBinNot, prefix_op_expr);
|
||||||
|
}
|
||||||
|
case CTokIdAsterisk:
|
||||||
|
{
|
||||||
|
*tok_i += 1;
|
||||||
|
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
||||||
|
if (prefix_op_expr == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
return trans_create_node_ptr_deref(c, prefix_op_expr);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return parse_ctok_suffix_op_expr(c, ctok, tok_i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) {
|
static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) {
|
||||||
|
@ -104,9 +104,7 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {
|
|||||||
|
|
||||||
var panicking: u8 = 0; // TODO make this a bool
|
var panicking: u8 = 0; // TODO make this a bool
|
||||||
|
|
||||||
pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize,
|
pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
|
||||||
comptime format: []const u8, args: ...) noreturn
|
|
||||||
{
|
|
||||||
@setCold(true);
|
@setCold(true);
|
||||||
|
|
||||||
if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
|
if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
|
||||||
@ -132,9 +130,7 @@ const WHITE = "\x1b[37;1m";
|
|||||||
const DIM = "\x1b[2m";
|
const DIM = "\x1b[2m";
|
||||||
const RESET = "\x1b[0m";
|
const RESET = "\x1b[0m";
|
||||||
|
|
||||||
pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator,
|
pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator, debug_info: &ElfStackTrace, tty_color: bool) !void {
|
||||||
debug_info: &ElfStackTrace, tty_color: bool) !void
|
|
||||||
{
|
|
||||||
var frame_index: usize = undefined;
|
var frame_index: usize = undefined;
|
||||||
var frames_left: usize = undefined;
|
var frames_left: usize = undefined;
|
||||||
if (stack_trace.index < stack_trace.instruction_addresses.len) {
|
if (stack_trace.index < stack_trace.instruction_addresses.len) {
|
||||||
@ -154,9 +150,7 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
|
pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator, debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void {
|
||||||
debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void
|
|
||||||
{
|
|
||||||
const AddressState = union(enum) {
|
const AddressState = union(enum) {
|
||||||
NotLookingForStartAddress,
|
NotLookingForStartAddress,
|
||||||
LookingForStartAddress: usize,
|
LookingForStartAddress: usize,
|
||||||
@ -166,14 +160,14 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
|
|||||||
// else AddressState.NotLookingForStartAddress;
|
// else AddressState.NotLookingForStartAddress;
|
||||||
var addr_state: AddressState = undefined;
|
var addr_state: AddressState = undefined;
|
||||||
if (start_addr) |addr| {
|
if (start_addr) |addr| {
|
||||||
addr_state = AddressState { .LookingForStartAddress = addr };
|
addr_state = AddressState{ .LookingForStartAddress = addr };
|
||||||
} else {
|
} else {
|
||||||
addr_state = AddressState.NotLookingForStartAddress;
|
addr_state = AddressState.NotLookingForStartAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fp = @ptrToInt(@frameAddress());
|
var fp = @ptrToInt(@frameAddress());
|
||||||
while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
|
while (fp != 0) : (fp = @intToPtr(&const usize, fp).*) {
|
||||||
const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
|
const return_address = @intToPtr(&const usize, fp + @sizeOf(usize)).*;
|
||||||
|
|
||||||
switch (addr_state) {
|
switch (addr_state) {
|
||||||
AddressState.NotLookingForStartAddress => {},
|
AddressState.NotLookingForStartAddress => {},
|
||||||
@ -200,32 +194,32 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us
|
|||||||
// in practice because the compiler dumps everything in a single
|
// in practice because the compiler dumps everything in a single
|
||||||
// object file. Future improvement: use external dSYM data when
|
// object file. Future improvement: use external dSYM data when
|
||||||
// available.
|
// available.
|
||||||
const unknown = macho.Symbol { .name = "???", .address = address };
|
const unknown = macho.Symbol{
|
||||||
|
.name = "???",
|
||||||
|
.address = address,
|
||||||
|
};
|
||||||
const symbol = debug_info.symbol_table.search(address) ?? &unknown;
|
const symbol = debug_info.symbol_table.search(address) ?? &unknown;
|
||||||
try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++
|
try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n", symbol.name, address);
|
||||||
DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n",
|
|
||||||
symbol.name, address);
|
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
const compile_unit = findCompileUnit(debug_info, address) catch {
|
const compile_unit = findCompileUnit(debug_info, address) catch {
|
||||||
try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
|
try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n", address);
|
||||||
address);
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
|
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
|
||||||
if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {
|
if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {
|
||||||
defer line_info.deinit();
|
defer line_info.deinit();
|
||||||
try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
|
try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n", line_info.file_name, line_info.line, line_info.column, address, compile_unit_name);
|
||||||
DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
|
|
||||||
line_info.file_name, line_info.line, line_info.column,
|
|
||||||
address, compile_unit_name);
|
|
||||||
if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {
|
if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {
|
||||||
if (line_info.column == 0) {
|
if (line_info.column == 0) {
|
||||||
try out_stream.write("\n");
|
try out_stream.write("\n");
|
||||||
} else {
|
} else {
|
||||||
{var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
|
{
|
||||||
try out_stream.writeByte(' ');
|
var col_i: usize = 1;
|
||||||
}}
|
while (col_i < line_info.column) : (col_i += 1) {
|
||||||
|
try out_stream.writeByte(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
|
try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
|
||||||
}
|
}
|
||||||
} else |err| switch (err) {
|
} else |err| switch (err) {
|
||||||
@ -233,7 +227,8 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us
|
|||||||
else => return err,
|
else => return err,
|
||||||
}
|
}
|
||||||
} else |err| switch (err) {
|
} else |err| switch (err) {
|
||||||
error.MissingDebugInfo, error.InvalidDebugInfo => {
|
error.MissingDebugInfo,
|
||||||
|
error.InvalidDebugInfo => {
|
||||||
try out_stream.print(ptr_hex ++ " in ??? ({})\n", address, compile_unit_name);
|
try out_stream.print(ptr_hex ++ " in ??? ({})\n", address, compile_unit_name);
|
||||||
},
|
},
|
||||||
else => return err,
|
else => return err,
|
||||||
@ -247,7 +242,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
|
|||||||
builtin.ObjectFormat.elf => {
|
builtin.ObjectFormat.elf => {
|
||||||
const st = try allocator.create(ElfStackTrace);
|
const st = try allocator.create(ElfStackTrace);
|
||||||
errdefer allocator.destroy(st);
|
errdefer allocator.destroy(st);
|
||||||
*st = ElfStackTrace {
|
st.* = ElfStackTrace{
|
||||||
.self_exe_file = undefined,
|
.self_exe_file = undefined,
|
||||||
.elf = undefined,
|
.elf = undefined,
|
||||||
.debug_info = undefined,
|
.debug_info = undefined,
|
||||||
@ -279,9 +274,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
|
|||||||
const st = try allocator.create(ElfStackTrace);
|
const st = try allocator.create(ElfStackTrace);
|
||||||
errdefer allocator.destroy(st);
|
errdefer allocator.destroy(st);
|
||||||
|
|
||||||
*st = ElfStackTrace {
|
st.* = ElfStackTrace{ .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)) };
|
||||||
.symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)),
|
|
||||||
};
|
|
||||||
|
|
||||||
return st;
|
return st;
|
||||||
},
|
},
|
||||||
@ -325,8 +318,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amt_read < buf.len)
|
if (amt_read < buf.len) return error.EndOfFile;
|
||||||
return error.EndOfFile;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,10 +410,8 @@ const Constant = struct {
|
|||||||
signed: bool,
|
signed: bool,
|
||||||
|
|
||||||
fn asUnsignedLe(self: &const Constant) !u64 {
|
fn asUnsignedLe(self: &const Constant) !u64 {
|
||||||
if (self.payload.len > @sizeOf(u64))
|
if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
|
||||||
return error.InvalidDebugInfo;
|
if (self.signed) return error.InvalidDebugInfo;
|
||||||
if (self.signed)
|
|
||||||
return error.InvalidDebugInfo;
|
|
||||||
return mem.readInt(self.payload, u64, builtin.Endian.Little);
|
return mem.readInt(self.payload, u64, builtin.Endian.Little);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -438,15 +428,14 @@ const Die = struct {
|
|||||||
|
|
||||||
fn getAttr(self: &const Die, id: u64) ?&const FormValue {
|
fn getAttr(self: &const Die, id: u64) ?&const FormValue {
|
||||||
for (self.attrs.toSliceConst()) |*attr| {
|
for (self.attrs.toSliceConst()) |*attr| {
|
||||||
if (attr.id == id)
|
if (attr.id == id) return &attr.value;
|
||||||
return &attr.value;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getAttrAddr(self: &const Die, id: u64) !u64 {
|
fn getAttrAddr(self: &const Die, id: u64) !u64 {
|
||||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
||||||
return switch (*form_value) {
|
return switch (form_value.*) {
|
||||||
FormValue.Address => |value| value,
|
FormValue.Address => |value| value,
|
||||||
else => error.InvalidDebugInfo,
|
else => error.InvalidDebugInfo,
|
||||||
};
|
};
|
||||||
@ -454,7 +443,7 @@ const Die = struct {
|
|||||||
|
|
||||||
fn getAttrSecOffset(self: &const Die, id: u64) !u64 {
|
fn getAttrSecOffset(self: &const Die, id: u64) !u64 {
|
||||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
||||||
return switch (*form_value) {
|
return switch (form_value.*) {
|
||||||
FormValue.Const => |value| value.asUnsignedLe(),
|
FormValue.Const => |value| value.asUnsignedLe(),
|
||||||
FormValue.SecOffset => |value| value,
|
FormValue.SecOffset => |value| value,
|
||||||
else => error.InvalidDebugInfo,
|
else => error.InvalidDebugInfo,
|
||||||
@ -463,7 +452,7 @@ const Die = struct {
|
|||||||
|
|
||||||
fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 {
|
fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 {
|
||||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
||||||
return switch (*form_value) {
|
return switch (form_value.*) {
|
||||||
FormValue.Const => |value| value.asUnsignedLe(),
|
FormValue.Const => |value| value.asUnsignedLe(),
|
||||||
else => error.InvalidDebugInfo,
|
else => error.InvalidDebugInfo,
|
||||||
};
|
};
|
||||||
@ -471,7 +460,7 @@ const Die = struct {
|
|||||||
|
|
||||||
fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 {
|
fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 {
|
||||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
||||||
return switch (*form_value) {
|
return switch (form_value.*) {
|
||||||
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,
|
||||||
@ -518,10 +507,8 @@ const LineNumberProgram = struct {
|
|||||||
prev_basic_block: bool,
|
prev_basic_block: bool,
|
||||||
prev_end_sequence: bool,
|
prev_end_sequence: bool,
|
||||||
|
|
||||||
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
|
return LineNumberProgram{
|
||||||
{
|
|
||||||
return LineNumberProgram {
|
|
||||||
.address = 0,
|
.address = 0,
|
||||||
.file = 1,
|
.file = 1,
|
||||||
.line = 1,
|
.line = 1,
|
||||||
@ -548,14 +535,16 @@ 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 &self.file_entries.items[self.prev_file - 1];
|
} else
|
||||||
|
&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 self.include_dirs[file_entry.dir_index];
|
} else
|
||||||
|
self.include_dirs[file_entry.dir_index];
|
||||||
const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
|
const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
|
||||||
errdefer self.file_entries.allocator.free(file_name);
|
errdefer self.file_entries.allocator.free(file_name);
|
||||||
return LineInfo {
|
return LineInfo{
|
||||||
.line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
|
.line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
|
||||||
.column = self.prev_column,
|
.column = self.prev_column,
|
||||||
.file_name = file_name,
|
.file_name = file_name,
|
||||||
@ -578,8 +567,7 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 {
|
|||||||
var buf = ArrayList(u8).init(allocator);
|
var buf = ArrayList(u8).init(allocator);
|
||||||
while (true) {
|
while (true) {
|
||||||
const byte = try in_stream.readByte();
|
const byte = try in_stream.readByte();
|
||||||
if (byte == 0)
|
if (byte == 0) break;
|
||||||
break;
|
|
||||||
try buf.append(byte);
|
try buf.append(byte);
|
||||||
}
|
}
|
||||||
return buf.toSlice();
|
return buf.toSlice();
|
||||||
@ -600,7 +588,7 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8
|
|||||||
|
|
||||||
fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
|
fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
|
||||||
const buf = try readAllocBytes(allocator, in_stream, size);
|
const buf = try readAllocBytes(allocator, in_stream, size);
|
||||||
return FormValue { .Block = buf };
|
return FormValue{ .Block = buf };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
|
fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
|
||||||
@ -609,26 +597,23 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
|
fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
|
||||||
return FormValue { .Const = Constant {
|
return FormValue{ .Const = Constant{
|
||||||
.signed = signed,
|
.signed = signed,
|
||||||
.payload = try readAllocBytes(allocator, in_stream, size),
|
.payload = try readAllocBytes(allocator, in_stream, size),
|
||||||
}};
|
} };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
|
fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
|
||||||
return if (is_64) try in_stream.readIntLe(u64)
|
return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32));
|
||||||
else u64(try in_stream.readIntLe(u32)) ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
|
fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
|
||||||
return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32))
|
return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable;
|
||||||
else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64)
|
|
||||||
else unreachable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
|
fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
|
||||||
const buf = try readAllocBytes(allocator, in_stream, size);
|
const buf = try readAllocBytes(allocator, in_stream, size);
|
||||||
return FormValue { .Ref = buf };
|
return FormValue{ .Ref = buf };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue {
|
fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue {
|
||||||
@ -646,11 +631,9 @@ const ParseFormValueError = error {
|
|||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool)
|
fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue {
|
||||||
ParseFormValueError!FormValue
|
|
||||||
{
|
|
||||||
return switch (form_id) {
|
return switch (form_id) {
|
||||||
DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) },
|
DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
|
||||||
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),
|
||||||
@ -662,7 +645,8 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
|
|||||||
DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
|
DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
|
||||||
DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
|
DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
|
||||||
DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
|
DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
|
||||||
DW.FORM_udata, DW.FORM_sdata => {
|
DW.FORM_udata,
|
||||||
|
DW.FORM_sdata => {
|
||||||
const block_len = try readULeb128(in_stream);
|
const block_len = try readULeb128(in_stream);
|
||||||
const signed = form_id == DW.FORM_sdata;
|
const signed = form_id == DW.FORM_sdata;
|
||||||
return parseFormValueConstant(allocator, in_stream, signed, block_len);
|
return parseFormValueConstant(allocator, in_stream, signed, block_len);
|
||||||
@ -670,11 +654,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
|
|||||||
DW.FORM_exprloc => {
|
DW.FORM_exprloc => {
|
||||||
const size = try readULeb128(in_stream);
|
const size = try readULeb128(in_stream);
|
||||||
const buf = try readAllocBytes(allocator, in_stream, size);
|
const buf = try readAllocBytes(allocator, in_stream, size);
|
||||||
return FormValue { .ExprLoc = buf };
|
return FormValue{ .ExprLoc = buf };
|
||||||
},
|
},
|
||||||
DW.FORM_flag => FormValue { .Flag = (try in_stream.readByte()) != 0 },
|
DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },
|
||||||
DW.FORM_flag_present => FormValue { .Flag = true },
|
DW.FORM_flag_present => FormValue{ .Flag = true },
|
||||||
DW.FORM_sec_offset => FormValue { .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||||
|
|
||||||
DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
|
DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
|
||||||
DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
|
DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
|
||||||
@ -685,11 +669,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
|
|||||||
return parseFormValueRefLen(allocator, in_stream, ref_len);
|
return parseFormValueRefLen(allocator, in_stream, ref_len);
|
||||||
},
|
},
|
||||||
|
|
||||||
DW.FORM_ref_addr => FormValue { .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||||
DW.FORM_ref_sig8 => FormValue { .RefSig8 = try in_stream.readIntLe(u64) },
|
DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) },
|
||||||
|
|
||||||
DW.FORM_string => FormValue { .String = try readStringRaw(allocator, in_stream) },
|
DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
|
||||||
DW.FORM_strp => FormValue { .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||||
DW.FORM_indirect => {
|
DW.FORM_indirect => {
|
||||||
const child_form_id = try readULeb128(in_stream);
|
const child_form_id = try readULeb128(in_stream);
|
||||||
return parseFormValue(allocator, in_stream, child_form_id, is_64);
|
return parseFormValue(allocator, in_stream, child_form_id, is_64);
|
||||||
@ -705,9 +689,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
|
|||||||
var result = AbbrevTable.init(st.allocator());
|
var result = AbbrevTable.init(st.allocator());
|
||||||
while (true) {
|
while (true) {
|
||||||
const abbrev_code = try readULeb128(in_stream);
|
const abbrev_code = try readULeb128(in_stream);
|
||||||
if (abbrev_code == 0)
|
if (abbrev_code == 0) return result;
|
||||||
return result;
|
try result.append(AbbrevTableEntry{
|
||||||
try result.append(AbbrevTableEntry {
|
|
||||||
.abbrev_code = abbrev_code,
|
.abbrev_code = abbrev_code,
|
||||||
.tag_id = try readULeb128(in_stream),
|
.tag_id = try readULeb128(in_stream),
|
||||||
.has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
|
.has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
|
||||||
@ -718,9 +701,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
|
|||||||
while (true) {
|
while (true) {
|
||||||
const attr_id = try readULeb128(in_stream);
|
const attr_id = try readULeb128(in_stream);
|
||||||
const form_id = try readULeb128(in_stream);
|
const form_id = try readULeb128(in_stream);
|
||||||
if (attr_id == 0 and form_id == 0)
|
if (attr_id == 0 and form_id == 0) break;
|
||||||
break;
|
try attrs.append(AbbrevAttr{
|
||||||
try attrs.append(AbbrevAttr {
|
|
||||||
.attr_id = attr_id,
|
.attr_id = attr_id,
|
||||||
.form_id = form_id,
|
.form_id = form_id,
|
||||||
});
|
});
|
||||||
@ -737,7 +719,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
|
try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
|
||||||
try st.abbrev_table_list.append(AbbrevTableHeader {
|
try st.abbrev_table_list.append(AbbrevTableHeader{
|
||||||
.offset = abbrev_offset,
|
.offset = abbrev_offset,
|
||||||
.table = try parseAbbrevTable(st),
|
.table = try parseAbbrevTable(st),
|
||||||
});
|
});
|
||||||
@ -746,8 +728,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
|
|||||||
|
|
||||||
fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&const AbbrevTableEntry {
|
fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&const AbbrevTableEntry {
|
||||||
for (abbrev_table.toSliceConst()) |*table_entry| {
|
for (abbrev_table.toSliceConst()) |*table_entry| {
|
||||||
if (table_entry.abbrev_code == abbrev_code)
|
if (table_entry.abbrev_code == abbrev_code) return table_entry;
|
||||||
return table_entry;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -759,14 +740,14 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !
|
|||||||
const abbrev_code = try readULeb128(in_stream);
|
const abbrev_code = try readULeb128(in_stream);
|
||||||
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
|
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
|
||||||
|
|
||||||
var result = Die {
|
var result = Die{
|
||||||
.tag_id = table_entry.tag_id,
|
.tag_id = table_entry.tag_id,
|
||||||
.has_children = table_entry.has_children,
|
.has_children = table_entry.has_children,
|
||||||
.attrs = ArrayList(Die.Attr).init(st.allocator()),
|
.attrs = ArrayList(Die.Attr).init(st.allocator()),
|
||||||
};
|
};
|
||||||
try result.attrs.resize(table_entry.attrs.len);
|
try result.attrs.resize(table_entry.attrs.len);
|
||||||
for (table_entry.attrs.toSliceConst()) |attr, i| {
|
for (table_entry.attrs.toSliceConst()) |attr, i| {
|
||||||
result.attrs.items[i] = Die.Attr {
|
result.attrs.items[i] = Die.Attr{
|
||||||
.id = attr.attr_id,
|
.id = attr.attr_id,
|
||||||
.value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
|
.value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
|
||||||
};
|
};
|
||||||
@ -790,8 +771,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||||||
|
|
||||||
var is_64: bool = undefined;
|
var is_64: bool = undefined;
|
||||||
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
|
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
|
||||||
if (unit_length == 0)
|
if (unit_length == 0) return error.MissingDebugInfo;
|
||||||
return error.MissingDebugInfo;
|
|
||||||
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
||||||
|
|
||||||
if (compile_unit.index != this_index) {
|
if (compile_unit.index != this_index) {
|
||||||
@ -803,8 +783,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||||||
// TODO support 3 and 5
|
// TODO support 3 and 5
|
||||||
if (version != 2 and version != 4) return error.InvalidDebugInfo;
|
if (version != 2 and version != 4) return error.InvalidDebugInfo;
|
||||||
|
|
||||||
const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64)
|
const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
|
||||||
else try in_stream.readInt(st.elf.endian, u32);
|
|
||||||
const prog_start_offset = (try in_file.getPos()) + prologue_length;
|
const prog_start_offset = (try in_file.getPos()) + prologue_length;
|
||||||
|
|
||||||
const minimum_instruction_length = try in_stream.readByte();
|
const minimum_instruction_length = try in_stream.readByte();
|
||||||
@ -819,38 +798,37 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||||||
const line_base = try in_stream.readByteSigned();
|
const line_base = try in_stream.readByteSigned();
|
||||||
|
|
||||||
const line_range = try in_stream.readByte();
|
const line_range = try in_stream.readByte();
|
||||||
if (line_range == 0)
|
if (line_range == 0) return error.InvalidDebugInfo;
|
||||||
return error.InvalidDebugInfo;
|
|
||||||
|
|
||||||
const opcode_base = try in_stream.readByte();
|
const opcode_base = try in_stream.readByte();
|
||||||
|
|
||||||
const standard_opcode_lengths = try st.allocator().alloc(u8, opcode_base - 1);
|
const standard_opcode_lengths = try st.allocator().alloc(u8, opcode_base - 1);
|
||||||
|
|
||||||
{var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
|
{
|
||||||
standard_opcode_lengths[i] = try in_stream.readByte();
|
var i: usize = 0;
|
||||||
}}
|
while (i < opcode_base - 1) : (i += 1) {
|
||||||
|
standard_opcode_lengths[i] = try in_stream.readByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var include_directories = ArrayList([]u8).init(st.allocator());
|
var include_directories = ArrayList([]u8).init(st.allocator());
|
||||||
try include_directories.append(compile_unit_cwd);
|
try include_directories.append(compile_unit_cwd);
|
||||||
while (true) {
|
while (true) {
|
||||||
const dir = try st.readString();
|
const dir = try st.readString();
|
||||||
if (dir.len == 0)
|
if (dir.len == 0) break;
|
||||||
break;
|
|
||||||
try include_directories.append(dir);
|
try include_directories.append(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_entries = ArrayList(FileEntry).init(st.allocator());
|
var file_entries = ArrayList(FileEntry).init(st.allocator());
|
||||||
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
|
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
|
||||||
&file_entries, target_address);
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const file_name = try st.readString();
|
const file_name = try st.readString();
|
||||||
if (file_name.len == 0)
|
if (file_name.len == 0) break;
|
||||||
break;
|
|
||||||
const dir_index = try readULeb128(in_stream);
|
const dir_index = try readULeb128(in_stream);
|
||||||
const mtime = try readULeb128(in_stream);
|
const mtime = try readULeb128(in_stream);
|
||||||
const len_bytes = try readULeb128(in_stream);
|
const len_bytes = try readULeb128(in_stream);
|
||||||
try file_entries.append(FileEntry {
|
try file_entries.append(FileEntry{
|
||||||
.file_name = file_name,
|
.file_name = file_name,
|
||||||
.dir_index = dir_index,
|
.dir_index = dir_index,
|
||||||
.mtime = mtime,
|
.mtime = mtime,
|
||||||
@ -866,8 +844,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||||||
var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
|
var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
|
||||||
if (opcode == DW.LNS_extended_op) {
|
if (opcode == DW.LNS_extended_op) {
|
||||||
const op_size = try readULeb128(in_stream);
|
const op_size = try readULeb128(in_stream);
|
||||||
if (op_size < 1)
|
if (op_size < 1) return error.InvalidDebugInfo;
|
||||||
return error.InvalidDebugInfo;
|
|
||||||
sub_op = try in_stream.readByte();
|
sub_op = try in_stream.readByte();
|
||||||
switch (sub_op) {
|
switch (sub_op) {
|
||||||
DW.LNE_end_sequence => {
|
DW.LNE_end_sequence => {
|
||||||
@ -884,7 +861,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||||||
const dir_index = try readULeb128(in_stream);
|
const dir_index = try readULeb128(in_stream);
|
||||||
const mtime = try readULeb128(in_stream);
|
const mtime = try readULeb128(in_stream);
|
||||||
const len_bytes = try readULeb128(in_stream);
|
const len_bytes = try readULeb128(in_stream);
|
||||||
try file_entries.append(FileEntry {
|
try file_entries.append(FileEntry{
|
||||||
.file_name = file_name,
|
.file_name = file_name,
|
||||||
.dir_index = dir_index,
|
.dir_index = dir_index,
|
||||||
.mtime = mtime,
|
.mtime = mtime,
|
||||||
@ -941,11 +918,9 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
|||||||
const arg = try in_stream.readInt(st.elf.endian, u16);
|
const arg = try in_stream.readInt(st.elf.endian, u16);
|
||||||
prog.address += arg;
|
prog.address += arg;
|
||||||
},
|
},
|
||||||
DW.LNS_set_prologue_end => {
|
DW.LNS_set_prologue_end => {},
|
||||||
},
|
|
||||||
else => {
|
else => {
|
||||||
if (opcode - 1 >= standard_opcode_lengths.len)
|
if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
|
||||||
return error.InvalidDebugInfo;
|
|
||||||
const len_bytes = standard_opcode_lengths[opcode - 1];
|
const len_bytes = standard_opcode_lengths[opcode - 1];
|
||||||
try in_file.seekForward(len_bytes);
|
try in_file.seekForward(len_bytes);
|
||||||
},
|
},
|
||||||
@ -972,16 +947,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
|
|||||||
|
|
||||||
var is_64: bool = undefined;
|
var is_64: bool = undefined;
|
||||||
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
|
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
|
||||||
if (unit_length == 0)
|
if (unit_length == 0) return;
|
||||||
return;
|
|
||||||
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
||||||
|
|
||||||
const version = try in_stream.readInt(st.elf.endian, u16);
|
const version = try 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 =
|
const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
|
||||||
if (is_64) try in_stream.readInt(st.elf.endian, u64)
|
|
||||||
else try in_stream.readInt(st.elf.endian, u32);
|
|
||||||
|
|
||||||
const address_size = try in_stream.readByte();
|
const address_size = try in_stream.readByte();
|
||||||
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
||||||
@ -992,15 +964,14 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
|
|||||||
try st.self_exe_file.seekTo(compile_unit_pos);
|
try st.self_exe_file.seekTo(compile_unit_pos);
|
||||||
|
|
||||||
const compile_unit_die = try st.allocator().create(Die);
|
const compile_unit_die = try st.allocator().create(Die);
|
||||||
*compile_unit_die = try parseDie(st, abbrev_table, is_64);
|
compile_unit_die.* = try parseDie(st, abbrev_table, is_64);
|
||||||
|
|
||||||
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 = x: {
|
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| b: {
|
FormValue.Const => |value| b: {
|
||||||
const offset = try value.asUnsignedLe();
|
const offset = try value.asUnsignedLe();
|
||||||
@ -1008,7 +979,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
|
|||||||
},
|
},
|
||||||
else => return error.InvalidDebugInfo,
|
else => return error.InvalidDebugInfo,
|
||||||
};
|
};
|
||||||
break :x PcRange {
|
break :x PcRange{
|
||||||
.start = low_pc,
|
.start = low_pc,
|
||||||
.end = pc_end,
|
.end = pc_end,
|
||||||
};
|
};
|
||||||
@ -1016,13 +987,12 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
|
|||||||
break :x null;
|
break :x null;
|
||||||
}
|
}
|
||||||
} else |err| {
|
} else |err| {
|
||||||
if (err != error.MissingDebugInfo)
|
if (err != error.MissingDebugInfo) return err;
|
||||||
return err;
|
|
||||||
break :x null;
|
break :x null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
try st.compile_unit_list.append(CompileUnit {
|
try st.compile_unit_list.append(CompileUnit{
|
||||||
.version = version,
|
.version = version,
|
||||||
.is_64 = is_64,
|
.is_64 = is_64,
|
||||||
.pc_range = pc_range,
|
.pc_range = pc_range,
|
||||||
@ -1040,8 +1010,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
|
|||||||
const in_stream = &in_file_stream.stream;
|
const in_stream = &in_file_stream.stream;
|
||||||
for (st.compile_unit_list.toSlice()) |*compile_unit| {
|
for (st.compile_unit_list.toSlice()) |*compile_unit| {
|
||||||
if (compile_unit.pc_range) |range| {
|
if (compile_unit.pc_range) |range| {
|
||||||
if (target_address >= range.start and target_address < range.end)
|
if (target_address >= range.start and target_address < range.end) return compile_unit;
|
||||||
return compile_unit;
|
|
||||||
}
|
}
|
||||||
if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
|
if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
|
||||||
var base_address: usize = 0;
|
var base_address: usize = 0;
|
||||||
@ -1063,8 +1032,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else |err| {
|
} else |err| {
|
||||||
if (err != error.MissingDebugInfo)
|
if (err != error.MissingDebugInfo) return err;
|
||||||
return err;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1073,8 +1041,8 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
|
|||||||
|
|
||||||
fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 {
|
fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 {
|
||||||
const first_32_bits = try in_stream.readIntLe(u32);
|
const first_32_bits = try in_stream.readIntLe(u32);
|
||||||
*is_64 = (first_32_bits == 0xffffffff);
|
is_64.* = (first_32_bits == 0xffffffff);
|
||||||
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;
|
||||||
@ -1091,13 +1059,11 @@ fn readULeb128(in_stream: var) !u64 {
|
|||||||
|
|
||||||
var operand: u64 = undefined;
|
var operand: u64 = undefined;
|
||||||
|
|
||||||
if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
|
if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand)) return error.InvalidDebugInfo;
|
||||||
return error.InvalidDebugInfo;
|
|
||||||
|
|
||||||
result |= operand;
|
result |= operand;
|
||||||
|
|
||||||
if ((byte & 0b10000000) == 0)
|
if ((byte & 0b10000000) == 0) return result;
|
||||||
return result;
|
|
||||||
|
|
||||||
shift += 7;
|
shift += 7;
|
||||||
}
|
}
|
||||||
@ -1112,15 +1078,13 @@ fn readILeb128(in_stream: var) !i64 {
|
|||||||
|
|
||||||
var operand: i64 = undefined;
|
var operand: i64 = undefined;
|
||||||
|
|
||||||
if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
|
if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand)) return error.InvalidDebugInfo;
|
||||||
return error.InvalidDebugInfo;
|
|
||||||
|
|
||||||
result |= operand;
|
result |= operand;
|
||||||
shift += 7;
|
shift += 7;
|
||||||
|
|
||||||
if ((byte & 0b10000000) == 0) {
|
if ((byte & 0b10000000) == 0) {
|
||||||
if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
|
if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << u6(shift));
|
||||||
result |= -(i64(1) << u6(shift));
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1131,7 +1095,6 @@ pub const global_allocator = &global_fixed_allocator.allocator;
|
|||||||
var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);
|
var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);
|
||||||
var global_allocator_mem: [100 * 1024]u8 = undefined;
|
var global_allocator_mem: [100 * 1024]u8 = undefined;
|
||||||
|
|
||||||
|
|
||||||
// TODO make thread safe
|
// TODO make thread safe
|
||||||
var debug_info_allocator: ?&mem.Allocator = null;
|
var debug_info_allocator: ?&mem.Allocator = null;
|
||||||
var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
|
var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
|
||||||
|
@ -47,12 +47,12 @@ pub fn forceEval(value: var) void {
|
|||||||
f32 => {
|
f32 => {
|
||||||
var x: f32 = undefined;
|
var x: f32 = undefined;
|
||||||
const p = @ptrCast(&volatile f32, &x);
|
const p = @ptrCast(&volatile f32, &x);
|
||||||
*p = x;
|
p.* = x;
|
||||||
},
|
},
|
||||||
f64 => {
|
f64 => {
|
||||||
var x: f64 = undefined;
|
var x: f64 = undefined;
|
||||||
const p = @ptrCast(&volatile f64, &x);
|
const p = @ptrCast(&volatile f64, &x);
|
||||||
*p = x;
|
p.* = x;
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
@compileError("forceEval not implemented for " ++ @typeName(T));
|
@compileError("forceEval not implemented for " ++ @typeName(T));
|
||||||
@ -179,7 +179,6 @@ test "math" {
|
|||||||
_ = @import("complex/index.zig");
|
_ = @import("complex/index.zig");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn min(x: var, y: var) @typeOf(x + y) {
|
pub fn min(x: var, y: var) @typeOf(x + y) {
|
||||||
return if (x < y) x else y;
|
return if (x < y) x else y;
|
||||||
}
|
}
|
||||||
@ -280,10 +279,10 @@ pub fn rotr(comptime T: type, x: T, r: var) T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "math.rotr" {
|
test "math.rotr" {
|
||||||
assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
|
assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
|
||||||
assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
|
assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
|
||||||
assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
|
assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
|
||||||
assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
|
assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
|
||||||
assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
|
assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,14 +298,13 @@ pub fn rotl(comptime T: type, x: T, r: var) T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "math.rotl" {
|
test "math.rotl" {
|
||||||
assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
|
assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
|
||||||
assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
|
assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
|
||||||
assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
|
assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
|
||||||
assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
|
assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
|
||||||
assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
|
assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn Log2Int(comptime T: type) type {
|
pub fn Log2Int(comptime T: type) type {
|
||||||
return @IntType(false, log2(T.bit_count));
|
return @IntType(false, log2(T.bit_count));
|
||||||
}
|
}
|
||||||
@ -323,14 +321,14 @@ fn testOverflow() void {
|
|||||||
assert((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
|
assert((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn absInt(x: var) !@typeOf(x) {
|
pub fn absInt(x: var) !@typeOf(x) {
|
||||||
const T = @typeOf(x);
|
const T = @typeOf(x);
|
||||||
comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
|
comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
|
||||||
comptime assert(T.is_signed); // must pass a signed integer to absInt
|
comptime assert(T.is_signed); // must pass a signed integer to absInt
|
||||||
if (x == @minValue(@typeOf(x)))
|
|
||||||
|
if (x == @minValue(@typeOf(x))) {
|
||||||
return error.Overflow;
|
return error.Overflow;
|
||||||
{
|
} else {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
return if (x < 0) -x else x;
|
return if (x < 0) -x else x;
|
||||||
}
|
}
|
||||||
@ -349,10 +347,8 @@ pub const absFloat = @import("fabs.zig").fabs;
|
|||||||
|
|
||||||
pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
|
pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
if (denominator == 0)
|
if (denominator == 0) return error.DivisionByZero;
|
||||||
return error.DivisionByZero;
|
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
|
||||||
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
|
|
||||||
return error.Overflow;
|
|
||||||
return @divTrunc(numerator, denominator);
|
return @divTrunc(numerator, denominator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,10 +368,8 @@ fn testDivTrunc() void {
|
|||||||
|
|
||||||
pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
|
pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
if (denominator == 0)
|
if (denominator == 0) return error.DivisionByZero;
|
||||||
return error.DivisionByZero;
|
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
|
||||||
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
|
|
||||||
return error.Overflow;
|
|
||||||
return @divFloor(numerator, denominator);
|
return @divFloor(numerator, denominator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,13 +389,10 @@ fn testDivFloor() void {
|
|||||||
|
|
||||||
pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
|
pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
if (denominator == 0)
|
if (denominator == 0) return error.DivisionByZero;
|
||||||
return error.DivisionByZero;
|
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
|
||||||
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
|
|
||||||
return error.Overflow;
|
|
||||||
const result = @divTrunc(numerator, denominator);
|
const result = @divTrunc(numerator, denominator);
|
||||||
if (result * denominator != numerator)
|
if (result * denominator != numerator) return error.UnexpectedRemainder;
|
||||||
return error.UnexpectedRemainder;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,10 +414,8 @@ fn testDivExact() void {
|
|||||||
|
|
||||||
pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
|
pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
if (denominator == 0)
|
if (denominator == 0) return error.DivisionByZero;
|
||||||
return error.DivisionByZero;
|
if (denominator < 0) return error.NegativeDenominator;
|
||||||
if (denominator < 0)
|
|
||||||
return error.NegativeDenominator;
|
|
||||||
return @mod(numerator, denominator);
|
return @mod(numerator, denominator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,10 +437,8 @@ fn testMod() void {
|
|||||||
|
|
||||||
pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
|
pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
if (denominator == 0)
|
if (denominator == 0) return error.DivisionByZero;
|
||||||
return error.DivisionByZero;
|
if (denominator < 0) return error.NegativeDenominator;
|
||||||
if (denominator < 0)
|
|
||||||
return error.NegativeDenominator;
|
|
||||||
return @rem(numerator, denominator);
|
return @rem(numerator, denominator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,8 +462,7 @@ fn testRem() void {
|
|||||||
/// Result is an unsigned integer.
|
/// Result is an unsigned integer.
|
||||||
pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {
|
pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {
|
||||||
const uint = @IntType(false, @typeOf(x).bit_count);
|
const uint = @IntType(false, @typeOf(x).bit_count);
|
||||||
if (x >= 0)
|
if (x >= 0) return uint(x);
|
||||||
return uint(x);
|
|
||||||
|
|
||||||
return uint(-(x + 1)) + 1;
|
return uint(-(x + 1)) + 1;
|
||||||
}
|
}
|
||||||
@ -495,15 +481,12 @@ test "math.absCast" {
|
|||||||
/// Returns the negation of the integer parameter.
|
/// Returns the negation of the integer parameter.
|
||||||
/// Result is a signed integer.
|
/// Result is a signed integer.
|
||||||
pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
|
pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
|
||||||
if (@typeOf(x).is_signed)
|
if (@typeOf(x).is_signed) return negate(x);
|
||||||
return negate(x);
|
|
||||||
|
|
||||||
const int = @IntType(true, @typeOf(x).bit_count);
|
const int = @IntType(true, @typeOf(x).bit_count);
|
||||||
if (x > -@minValue(int))
|
if (x > -@minValue(int)) return error.Overflow;
|
||||||
return error.Overflow;
|
|
||||||
|
|
||||||
if (x == -@minValue(int))
|
if (x == -@minValue(int)) return @minValue(int);
|
||||||
return @minValue(int);
|
|
||||||
|
|
||||||
return -int(x);
|
return -int(x);
|
||||||
}
|
}
|
||||||
@ -546,7 +529,7 @@ pub fn floorPowerOfTwo(comptime T: type, value: T) T {
|
|||||||
var x = value;
|
var x = value;
|
||||||
|
|
||||||
comptime var i = 1;
|
comptime var i = 1;
|
||||||
inline while(T.bit_count > i) : (i *= 2) {
|
inline while (T.bit_count > i) : (i *= 2) {
|
||||||
x |= (x >> i);
|
x |= (x >> i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
197
std/mem.zig
197
std/mem.zig
@ -6,14 +6,14 @@ const builtin = @import("builtin");
|
|||||||
const mem = this;
|
const mem = this;
|
||||||
|
|
||||||
pub const Allocator = struct {
|
pub const Allocator = struct {
|
||||||
const Error = error {OutOfMemory};
|
const Error = error{OutOfMemory};
|
||||||
|
|
||||||
/// Allocate byte_count bytes and return them in a slice, with the
|
/// Allocate byte_count bytes and return them in a slice, with the
|
||||||
/// slice's pointer aligned at least to alignment bytes.
|
/// slice's pointer aligned at least to alignment bytes.
|
||||||
/// The returned newly allocated memory is undefined.
|
/// The returned newly allocated memory is undefined.
|
||||||
/// `alignment` is guaranteed to be >= 1
|
/// `alignment` is guaranteed to be >= 1
|
||||||
/// `alignment` is guaranteed to be a power of 2
|
/// `alignment` is guaranteed to be a power of 2
|
||||||
allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
|
allocFn: fn(self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
|
||||||
|
|
||||||
/// If `new_byte_count > old_mem.len`:
|
/// If `new_byte_count > old_mem.len`:
|
||||||
/// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
|
/// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
|
||||||
@ -26,10 +26,10 @@ pub const Allocator = struct {
|
|||||||
/// The returned newly allocated memory is undefined.
|
/// The returned newly allocated memory is undefined.
|
||||||
/// `alignment` is guaranteed to be >= 1
|
/// `alignment` is guaranteed to be >= 1
|
||||||
/// `alignment` is guaranteed to be a power of 2
|
/// `alignment` is guaranteed to be a power of 2
|
||||||
reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
|
reallocFn: fn(self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
|
||||||
|
|
||||||
/// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
|
/// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
|
||||||
freeFn: fn (self: &Allocator, old_mem: []u8) void,
|
freeFn: fn(self: &Allocator, old_mem: []u8) void,
|
||||||
|
|
||||||
fn create(self: &Allocator, comptime T: type) !&T {
|
fn create(self: &Allocator, comptime T: type) !&T {
|
||||||
if (@sizeOf(T) == 0) return &{};
|
if (@sizeOf(T) == 0) return &{};
|
||||||
@ -47,7 +47,7 @@ pub const Allocator = struct {
|
|||||||
if (@sizeOf(T) == 0) return &{};
|
if (@sizeOf(T) == 0) return &{};
|
||||||
const slice = try self.alloc(T, 1);
|
const slice = try self.alloc(T, 1);
|
||||||
const ptr = &slice[0];
|
const ptr = &slice[0];
|
||||||
*ptr = *init;
|
ptr.* = init.*;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,9 +59,7 @@ pub const Allocator = struct {
|
|||||||
return self.alignedAlloc(T, @alignOf(T), n);
|
return self.alignedAlloc(T, @alignOf(T), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
|
fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29, n: usize) ![]align(alignment) T {
|
||||||
n: usize) ![]align(alignment) T
|
|
||||||
{
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
return (&align(alignment) T)(undefined)[0..0];
|
return (&align(alignment) T)(undefined)[0..0];
|
||||||
}
|
}
|
||||||
@ -70,7 +68,7 @@ pub const Allocator = struct {
|
|||||||
assert(byte_slice.len == byte_count);
|
assert(byte_slice.len == byte_count);
|
||||||
// This loop gets optimized out in ReleaseFast mode
|
// This loop gets optimized out in ReleaseFast mode
|
||||||
for (byte_slice) |*byte| {
|
for (byte_slice) |*byte| {
|
||||||
*byte = undefined;
|
byte.* = undefined;
|
||||||
}
|
}
|
||||||
return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
|
return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
|
||||||
}
|
}
|
||||||
@ -79,9 +77,7 @@ pub const Allocator = struct {
|
|||||||
return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
|
return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29,
|
fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) ![]align(alignment) T {
|
||||||
old_mem: []align(alignment) T, n: usize) ![]align(alignment) T
|
|
||||||
{
|
|
||||||
if (old_mem.len == 0) {
|
if (old_mem.len == 0) {
|
||||||
return self.alloc(T, n);
|
return self.alloc(T, n);
|
||||||
}
|
}
|
||||||
@ -97,7 +93,7 @@ pub const Allocator = struct {
|
|||||||
if (n > old_mem.len) {
|
if (n > old_mem.len) {
|
||||||
// This loop gets optimized out in ReleaseFast mode
|
// This loop gets optimized out in ReleaseFast mode
|
||||||
for (byte_slice[old_byte_slice.len..]) |*byte| {
|
for (byte_slice[old_byte_slice.len..]) |*byte| {
|
||||||
*byte = undefined;
|
byte.* = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ([]T)(@alignCast(alignment, byte_slice));
|
return ([]T)(@alignCast(alignment, byte_slice));
|
||||||
@ -110,9 +106,7 @@ pub const Allocator = struct {
|
|||||||
return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
|
return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29,
|
fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) []align(alignment) T {
|
||||||
old_mem: []align(alignment) T, n: usize) []align(alignment) T
|
|
||||||
{
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
self.free(old_mem);
|
self.free(old_mem);
|
||||||
return old_mem[0..0];
|
return old_mem[0..0];
|
||||||
@ -131,8 +125,7 @@ pub const Allocator = struct {
|
|||||||
|
|
||||||
fn free(self: &Allocator, memory: var) void {
|
fn free(self: &Allocator, memory: var) void {
|
||||||
const bytes = ([]const u8)(memory);
|
const bytes = ([]const u8)(memory);
|
||||||
if (bytes.len == 0)
|
if (bytes.len == 0) return;
|
||||||
return;
|
|
||||||
const non_const_ptr = @intToPtr(&u8, @ptrToInt(bytes.ptr));
|
const non_const_ptr = @intToPtr(&u8, @ptrToInt(bytes.ptr));
|
||||||
self.freeFn(self, non_const_ptr[0..bytes.len]);
|
self.freeFn(self, non_const_ptr[0..bytes.len]);
|
||||||
}
|
}
|
||||||
@ -146,11 +139,13 @@ pub fn copy(comptime T: type, dest: []T, source: []const T) void {
|
|||||||
// this and automatically omit safety checks for loops
|
// this and automatically omit safety checks for loops
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
assert(dest.len >= source.len);
|
assert(dest.len >= source.len);
|
||||||
for (source) |s, i| dest[i] = s;
|
for (source) |s, i|
|
||||||
|
dest[i] = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(comptime T: type, dest: []T, value: T) void {
|
pub fn set(comptime T: type, dest: []T, value: T) void {
|
||||||
for (dest) |*d| *d = value;
|
for (dest) |*d|
|
||||||
|
d.* = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if lhs < rhs, false otherwise
|
/// Returns true if lhs < rhs, false otherwise
|
||||||
@ -229,8 +224,7 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
|
|||||||
var i: usize = slice.len;
|
var i: usize = slice.len;
|
||||||
while (i != 0) {
|
while (i != 0) {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
if (slice[i] == value)
|
if (slice[i] == value) return i;
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -238,8 +232,7 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
|
|||||||
pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
|
pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
|
||||||
var i: usize = start_index;
|
var i: usize = start_index;
|
||||||
while (i < slice.len) : (i += 1) {
|
while (i < slice.len) : (i += 1) {
|
||||||
if (slice[i] == value)
|
if (slice[i] == value) return i;
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -253,8 +246,7 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us
|
|||||||
while (i != 0) {
|
while (i != 0) {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
for (values) |value| {
|
for (values) |value| {
|
||||||
if (slice[i] == value)
|
if (slice[i] == value) return i;
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -264,8 +256,7 @@ pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, val
|
|||||||
var i: usize = start_index;
|
var i: usize = start_index;
|
||||||
while (i < slice.len) : (i += 1) {
|
while (i < slice.len) : (i += 1) {
|
||||||
for (values) |value| {
|
for (values) |value| {
|
||||||
if (slice[i] == value)
|
if (slice[i] == value) return i;
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -279,28 +270,23 @@ pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
|
|||||||
/// To start looking at a different index, slice the haystack first.
|
/// To start looking at a different index, slice the haystack first.
|
||||||
/// TODO is there even a better algorithm for this?
|
/// TODO is there even a better algorithm for this?
|
||||||
pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
|
pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
|
||||||
if (needle.len > haystack.len)
|
if (needle.len > haystack.len) return null;
|
||||||
return null;
|
|
||||||
|
|
||||||
var i: usize = haystack.len - needle.len;
|
var i: usize = haystack.len - needle.len;
|
||||||
while (true) : (i -= 1) {
|
while (true) : (i -= 1) {
|
||||||
if (mem.eql(T, haystack[i..i+needle.len], needle))
|
if (mem.eql(T, haystack[i..i + needle.len], needle)) return i;
|
||||||
return i;
|
if (i == 0) return null;
|
||||||
if (i == 0)
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO boyer-moore algorithm
|
// TODO boyer-moore algorithm
|
||||||
pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
|
pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
|
||||||
if (needle.len > haystack.len)
|
if (needle.len > haystack.len) return null;
|
||||||
return null;
|
|
||||||
|
|
||||||
var i: usize = start_index;
|
var i: usize = start_index;
|
||||||
const end = haystack.len - needle.len;
|
const end = haystack.len - needle.len;
|
||||||
while (i <= end) : (i += 1) {
|
while (i <= end) : (i += 1) {
|
||||||
if (eql(T, haystack[i .. i + needle.len], needle))
|
if (eql(T, haystack[i..i + needle.len], needle)) return i;
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -355,9 +341,12 @@ pub fn readIntBE(comptime T: type, bytes: []const u8) T {
|
|||||||
}
|
}
|
||||||
assert(bytes.len == @sizeOf(T));
|
assert(bytes.len == @sizeOf(T));
|
||||||
var result: T = 0;
|
var result: T = 0;
|
||||||
{comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
|
{
|
||||||
result = (result << 8) | T(bytes[i]);
|
comptime var i = 0;
|
||||||
}}
|
inline while (i < @sizeOf(T)) : (i += 1) {
|
||||||
|
result = (result << 8) | T(bytes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,9 +358,12 @@ pub fn readIntLE(comptime T: type, bytes: []const u8) T {
|
|||||||
}
|
}
|
||||||
assert(bytes.len == @sizeOf(T));
|
assert(bytes.len == @sizeOf(T));
|
||||||
var result: T = 0;
|
var result: T = 0;
|
||||||
{comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
|
{
|
||||||
result |= T(bytes[i]) << i * 8;
|
comptime var i = 0;
|
||||||
}}
|
inline while (i < @sizeOf(T)) : (i += 1) {
|
||||||
|
result |= T(bytes[i]) << i * 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +385,7 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
|
|||||||
},
|
},
|
||||||
builtin.Endian.Little => {
|
builtin.Endian.Little => {
|
||||||
for (buf) |*b| {
|
for (buf) |*b| {
|
||||||
*b = @truncate(u8, bits);
|
b.* = @truncate(u8, bits);
|
||||||
bits >>= 8;
|
bits >>= 8;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -401,7 +393,6 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
|
|||||||
assert(bits == 0);
|
assert(bits == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn hash_slice_u8(k: []const u8) u32 {
|
pub fn hash_slice_u8(k: []const u8) u32 {
|
||||||
// FNV 32-bit hash
|
// FNV 32-bit hash
|
||||||
var h: u32 = 2166136261;
|
var h: u32 = 2166136261;
|
||||||
@ -420,7 +411,7 @@ 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 {
|
||||||
return SplitIterator {
|
return SplitIterator{
|
||||||
.index = 0,
|
.index = 0,
|
||||||
.buffer = buffer,
|
.buffer = buffer,
|
||||||
.split_bytes = split_bytes,
|
.split_bytes = split_bytes,
|
||||||
@ -436,7 +427,7 @@ test "mem.split" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
|
pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
|
||||||
return if (needle.len > haystack.len) false else eql(T, haystack[0 .. needle.len], needle);
|
return if (needle.len > haystack.len) false else eql(T, haystack[0..needle.len], needle);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "mem.startsWith" {
|
test "mem.startsWith" {
|
||||||
@ -445,10 +436,9 @@ test "mem.startsWith" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
|
pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
|
||||||
return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len ..], needle);
|
return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len..], needle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "mem.endsWith" {
|
test "mem.endsWith" {
|
||||||
assert(endsWith(u8, "Needle in haystack", "haystack"));
|
assert(endsWith(u8, "Needle in haystack", "haystack"));
|
||||||
assert(!endsWith(u8, "Bob", "Bo"));
|
assert(!endsWith(u8, "Bob", "Bo"));
|
||||||
@ -542,29 +532,47 @@ test "testReadInt" {
|
|||||||
}
|
}
|
||||||
fn testReadIntImpl() void {
|
fn testReadIntImpl() void {
|
||||||
{
|
{
|
||||||
const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 };
|
const bytes = []u8{
|
||||||
assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
|
0x12,
|
||||||
assert(readIntBE(u32, bytes) == 0x12345678);
|
0x34,
|
||||||
assert(readIntBE(i32, bytes) == 0x12345678);
|
0x56,
|
||||||
|
0x78,
|
||||||
|
};
|
||||||
|
assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
|
||||||
|
assert(readIntBE(u32, bytes) == 0x12345678);
|
||||||
|
assert(readIntBE(i32, bytes) == 0x12345678);
|
||||||
assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);
|
assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);
|
||||||
assert(readIntLE(u32, bytes) == 0x78563412);
|
assert(readIntLE(u32, bytes) == 0x78563412);
|
||||||
assert(readIntLE(i32, bytes) == 0x78563412);
|
assert(readIntLE(i32, bytes) == 0x78563412);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const buf = []u8{0x00, 0x00, 0x12, 0x34};
|
const buf = []u8{
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x12,
|
||||||
|
0x34,
|
||||||
|
};
|
||||||
const answer = readInt(buf, u64, builtin.Endian.Big);
|
const answer = readInt(buf, u64, builtin.Endian.Big);
|
||||||
assert(answer == 0x00001234);
|
assert(answer == 0x00001234);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const buf = []u8{0x12, 0x34, 0x00, 0x00};
|
const buf = []u8{
|
||||||
|
0x12,
|
||||||
|
0x34,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
const answer = readInt(buf, u64, builtin.Endian.Little);
|
const answer = readInt(buf, u64, builtin.Endian.Little);
|
||||||
assert(answer == 0x00003412);
|
assert(answer == 0x00003412);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const bytes = []u8{0xff, 0xfe};
|
const bytes = []u8{
|
||||||
assert(readIntBE(u16, bytes) == 0xfffe);
|
0xff,
|
||||||
|
0xfe,
|
||||||
|
};
|
||||||
|
assert(readIntBE(u16, bytes) == 0xfffe);
|
||||||
assert(readIntBE(i16, bytes) == -0x0002);
|
assert(readIntBE(i16, bytes) == -0x0002);
|
||||||
assert(readIntLE(u16, bytes) == 0xfeff);
|
assert(readIntLE(u16, bytes) == 0xfeff);
|
||||||
assert(readIntLE(i16, bytes) == -0x0101);
|
assert(readIntLE(i16, bytes) == -0x0101);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -577,19 +585,38 @@ fn testWriteIntImpl() void {
|
|||||||
var bytes: [4]u8 = undefined;
|
var bytes: [4]u8 = undefined;
|
||||||
|
|
||||||
writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);
|
writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);
|
||||||
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
|
assert(eql(u8, bytes, []u8{
|
||||||
|
0x12,
|
||||||
|
0x34,
|
||||||
|
0x56,
|
||||||
|
0x78,
|
||||||
|
}));
|
||||||
|
|
||||||
writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);
|
writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);
|
||||||
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
|
assert(eql(u8, bytes, []u8{
|
||||||
|
0x12,
|
||||||
|
0x34,
|
||||||
|
0x56,
|
||||||
|
0x78,
|
||||||
|
}));
|
||||||
|
|
||||||
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);
|
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);
|
||||||
assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 }));
|
assert(eql(u8, bytes, []u8{
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x12,
|
||||||
|
0x34,
|
||||||
|
}));
|
||||||
|
|
||||||
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);
|
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);
|
||||||
assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 }));
|
assert(eql(u8, bytes, []u8{
|
||||||
|
0x34,
|
||||||
|
0x12,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn min(comptime T: type, slice: []const T) T {
|
pub fn min(comptime T: type, slice: []const T) T {
|
||||||
var best = slice[0];
|
var best = slice[0];
|
||||||
for (slice[1..]) |item| {
|
for (slice[1..]) |item| {
|
||||||
@ -615,9 +642,9 @@ test "mem.max" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn swap(comptime T: type, a: &T, b: &T) void {
|
pub fn swap(comptime T: type, a: &T, b: &T) void {
|
||||||
const tmp = *a;
|
const tmp = a.*;
|
||||||
*a = *b;
|
a.* = b.*;
|
||||||
*b = tmp;
|
b.* = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In-place order reversal of a slice
|
/// In-place order reversal of a slice
|
||||||
@ -630,10 +657,22 @@ pub fn reverse(comptime T: type, items: []T) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "std.mem.reverse" {
|
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)
|
||||||
@ -645,10 +684,22 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "std.mem.rotate" {
|
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,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by
|
// TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by
|
||||||
|
@ -3705,7 +3705,9 @@ pub const Parser = struct {
|
|||||||
},
|
},
|
||||||
ast.Node.Id.PrefixOp => {
|
ast.Node.Id.PrefixOp => {
|
||||||
const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
|
const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
|
||||||
try stack.append(RenderState { .Expression = prefix_op_node.rhs });
|
if (prefix_op_node.op != ast.Node.PrefixOp.Op.Deref) {
|
||||||
|
try stack.append(RenderState { .Expression = prefix_op_node.rhs });
|
||||||
|
}
|
||||||
switch (prefix_op_node.op) {
|
switch (prefix_op_node.op) {
|
||||||
ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
|
ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
|
||||||
try stream.write("&");
|
try stream.write("&");
|
||||||
@ -3742,7 +3744,10 @@ pub const Parser = struct {
|
|||||||
},
|
},
|
||||||
ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
|
ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
|
||||||
ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
|
ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
|
||||||
ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
|
ast.Node.PrefixOp.Op.Deref => {
|
||||||
|
try stack.append(RenderState { .Text = ".*" });
|
||||||
|
try stack.append(RenderState { .Expression = prefix_op_node.rhs });
|
||||||
|
},
|
||||||
ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
|
ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
|
||||||
ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
|
ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
|
||||||
ast.Node.PrefixOp.Op.Try => try stream.write("try "),
|
ast.Node.PrefixOp.Op.Try => try stream.write("try "),
|
||||||
|
@ -10,7 +10,9 @@ test "global variable alignment" {
|
|||||||
assert(@typeOf(slice) == []align(4) u8);
|
assert(@typeOf(slice) == []align(4) u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
|
fn derp() align(@sizeOf(usize) * 2) i32 {
|
||||||
|
return 1234;
|
||||||
|
}
|
||||||
fn noop1() align(1) void {}
|
fn noop1() align(1) void {}
|
||||||
fn noop4() align(4) void {}
|
fn noop4() align(4) void {}
|
||||||
|
|
||||||
@ -22,7 +24,6 @@ test "function alignment" {
|
|||||||
noop4();
|
noop4();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var baz: packed struct {
|
var baz: packed struct {
|
||||||
a: u32,
|
a: u32,
|
||||||
b: u32,
|
b: u32,
|
||||||
@ -32,7 +33,6 @@ test "packed struct alignment" {
|
|||||||
assert(@typeOf(&baz.b) == &align(1) u32);
|
assert(@typeOf(&baz.b) == &align(1) u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const blah: packed struct {
|
const blah: packed struct {
|
||||||
a: u3,
|
a: u3,
|
||||||
b: u3,
|
b: u3,
|
||||||
@ -53,29 +53,43 @@ 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 { return *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 { return 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);
|
||||||
}
|
}
|
||||||
fn testBytesAlign(b: u8) void {
|
fn testBytesAlign(b: u8) void {
|
||||||
var bytes align(4) = []u8{b, b, b, b};
|
var bytes align(4) = []u8 {
|
||||||
|
b,
|
||||||
|
b,
|
||||||
|
b,
|
||||||
|
b,
|
||||||
|
};
|
||||||
const ptr = @ptrCast(&u32, &bytes[0]);
|
const ptr = @ptrCast(&u32, &bytes[0]);
|
||||||
assert(*ptr == 0x33333333);
|
assert(ptr.* == 0x33333333);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "specifying alignment allows slice cast" {
|
test "specifying alignment allows slice cast" {
|
||||||
testBytesAlignSlice(0x33);
|
testBytesAlignSlice(0x33);
|
||||||
}
|
}
|
||||||
fn testBytesAlignSlice(b: u8) void {
|
fn testBytesAlignSlice(b: u8) void {
|
||||||
var bytes align(4) = []u8{b, b, b, b};
|
var bytes align(4) = []u8 {
|
||||||
|
b,
|
||||||
|
b,
|
||||||
|
b,
|
||||||
|
b,
|
||||||
|
};
|
||||||
const slice = ([]u32)(bytes[0..]);
|
const slice = ([]u32)(bytes[0..]);
|
||||||
assert(slice[0] == 0x33333333);
|
assert(slice[0] == 0x33333333);
|
||||||
}
|
}
|
||||||
@ -89,11 +103,14 @@ fn expectsOnly1(x: &align(1) u32) void {
|
|||||||
expects4(@alignCast(4, x));
|
expects4(@alignCast(4, x));
|
||||||
}
|
}
|
||||||
fn expects4(x: &align(4) u32) void {
|
fn expects4(x: &align(4) u32) void {
|
||||||
*x += 1;
|
x.* += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@alignCast slices" {
|
test "@alignCast slices" {
|
||||||
var array align(4) = []u32{1, 1};
|
var array align(4) = []u32 {
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
};
|
||||||
const slice = array[0..];
|
const slice = array[0..];
|
||||||
sliceExpectsOnly1(slice);
|
sliceExpectsOnly1(slice);
|
||||||
assert(slice[0] == 2);
|
assert(slice[0] == 2);
|
||||||
@ -105,31 +122,34 @@ fn sliceExpects4(slice: []align(4) u32) void {
|
|||||||
slice[0] += 1;
|
slice[0] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "implicitly decreasing fn alignment" {
|
test "implicitly decreasing fn alignment" {
|
||||||
testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
|
testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
|
||||||
testImplicitlyDecreaseFnAlign(alignedBig, 5678);
|
testImplicitlyDecreaseFnAlign(alignedBig, 5678);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void {
|
fn testImplicitlyDecreaseFnAlign(ptr: fn() align(1) i32, answer: i32) void {
|
||||||
assert(ptr() == answer);
|
assert(ptr() == answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alignedSmall() align(8) i32 { return 1234; }
|
fn alignedSmall() align(8) i32 {
|
||||||
fn alignedBig() align(16) i32 { return 5678; }
|
return 1234;
|
||||||
|
}
|
||||||
|
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 {
|
||||||
return 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 {
|
||||||
return ptr();
|
return ptr();
|
||||||
}
|
}
|
||||||
fn simple4() align(4) i32 { return 0x19; }
|
fn simple4() align(4) i32 {
|
||||||
|
return 0x19;
|
||||||
|
}
|
||||||
|
|
||||||
test "generic function with align param" {
|
test "generic function with align param" {
|
||||||
assert(whyWouldYouEverDoThis(1) == 0x1);
|
assert(whyWouldYouEverDoThis(1) == 0x1);
|
||||||
@ -137,8 +157,9 @@ test "generic function with align param" {
|
|||||||
assert(whyWouldYouEverDoThis(8) == 0x1);
|
assert(whyWouldYouEverDoThis(8) == 0x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { return 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" {
|
||||||
var x: u32 align(16) = 1234;
|
var x: u32 align(16) = 1234;
|
||||||
@ -146,24 +167,38 @@ test "@ptrCast preserves alignment of bigger source" {
|
|||||||
assert(@typeOf(ptr) == &align(16) u8);
|
assert(@typeOf(ptr) == &align(16) u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "compile-time known array index has best alignment possible" {
|
test "compile-time known array index has best alignment possible" {
|
||||||
// take full advantage of over-alignment
|
// take full advantage of over-alignment
|
||||||
var array align(4) = []u8 {1, 2, 3, 4};
|
var array align(4) = []u8 {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
};
|
||||||
assert(@typeOf(&array[0]) == &align(4) u8);
|
assert(@typeOf(&array[0]) == &align(4) u8);
|
||||||
assert(@typeOf(&array[1]) == &u8);
|
assert(@typeOf(&array[1]) == &u8);
|
||||||
assert(@typeOf(&array[2]) == &align(2) u8);
|
assert(@typeOf(&array[2]) == &align(2) u8);
|
||||||
assert(@typeOf(&array[3]) == &u8);
|
assert(@typeOf(&array[3]) == &u8);
|
||||||
|
|
||||||
// because align is too small but we still figure out to use 2
|
// because align is too small but we still figure out to use 2
|
||||||
var bigger align(2) = []u64{1, 2, 3, 4};
|
var bigger align(2) = []u64 {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
};
|
||||||
assert(@typeOf(&bigger[0]) == &align(2) u64);
|
assert(@typeOf(&bigger[0]) == &align(2) u64);
|
||||||
assert(@typeOf(&bigger[1]) == &align(2) u64);
|
assert(@typeOf(&bigger[1]) == &align(2) u64);
|
||||||
assert(@typeOf(&bigger[2]) == &align(2) u64);
|
assert(@typeOf(&bigger[2]) == &align(2) u64);
|
||||||
assert(@typeOf(&bigger[3]) == &align(2) u64);
|
assert(@typeOf(&bigger[3]) == &align(2) u64);
|
||||||
|
|
||||||
// because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
|
// because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
|
||||||
var smaller align(2) = []u32{1, 2, 3, 4};
|
var smaller align(2) = []u32 {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
};
|
||||||
testIndex(&smaller[0], 0, &align(2) u32);
|
testIndex(&smaller[0], 0, &align(2) u32);
|
||||||
testIndex(&smaller[0], 1, &align(2) u32);
|
testIndex(&smaller[0], 1, &align(2) u32);
|
||||||
testIndex(&smaller[0], 2, &align(2) u32);
|
testIndex(&smaller[0], 2, &align(2) u32);
|
||||||
@ -182,7 +217,6 @@ fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) void {
|
|||||||
assert(@typeOf(&ptr[index]) == T);
|
assert(@typeOf(&ptr[index]) == T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "alignstack" {
|
test "alignstack" {
|
||||||
assert(fnWithAlignedStack() == 1234);
|
assert(fnWithAlignedStack() == 1234);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
const assert = @import("std").debug.assert;
|
const assert = @import("std").debug.assert;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
const Foo = struct { x: u32, y: u32, z: u32, };
|
const Foo = struct {
|
||||||
|
x: u32,
|
||||||
|
y: u32,
|
||||||
|
z: u32,
|
||||||
|
};
|
||||||
|
|
||||||
test "@alignOf(T) before referencing T" {
|
test "@alignOf(T) before referencing T" {
|
||||||
comptime assert(@alignOf(Foo) != @maxValue(usize));
|
comptime assert(@alignOf(Foo) != @maxValue(usize));
|
||||||
|
@ -2,9 +2,9 @@ const assert = @import("std").debug.assert;
|
|||||||
const mem = @import("std").mem;
|
const mem = @import("std").mem;
|
||||||
|
|
||||||
test "arrays" {
|
test "arrays" {
|
||||||
var array : [5]u32 = undefined;
|
var array: [5]u32 = undefined;
|
||||||
|
|
||||||
var i : u32 = 0;
|
var i: u32 = 0;
|
||||||
while (i < 5) {
|
while (i < 5) {
|
||||||
array[i] = i + 1;
|
array[i] = i + 1;
|
||||||
i = array[i];
|
i = array[i];
|
||||||
@ -34,24 +34,41 @@ test "void arrays" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "array literal" {
|
test "array literal" {
|
||||||
const hex_mult = []u16{4096, 256, 16, 1};
|
const hex_mult = []u16 {
|
||||||
|
4096,
|
||||||
|
256,
|
||||||
|
16,
|
||||||
|
1,
|
||||||
|
};
|
||||||
|
|
||||||
assert(hex_mult.len == 4);
|
assert(hex_mult.len == 4);
|
||||||
assert(hex_mult[1] == 256);
|
assert(hex_mult[1] == 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "array dot len const expr" {
|
test "array dot len const expr" {
|
||||||
assert(comptime x: {break :x some_array.len == 4;});
|
assert(comptime x: {
|
||||||
|
break :x some_array.len == 4;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const ArrayDotLenConstExpr = struct {
|
const ArrayDotLenConstExpr = struct {
|
||||||
y: [some_array.len]u8,
|
y: [some_array.len]u8,
|
||||||
};
|
};
|
||||||
const some_array = []u8 {0, 1, 2, 3};
|
const some_array = []u8 {
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
};
|
||||||
|
|
||||||
test "nested arrays" {
|
test "nested arrays" {
|
||||||
const array_of_strings = [][]const u8 {"hello", "this", "is", "my", "thing"};
|
const array_of_strings = [][]const u8 {
|
||||||
|
"hello",
|
||||||
|
"this",
|
||||||
|
"is",
|
||||||
|
"my",
|
||||||
|
"thing",
|
||||||
|
};
|
||||||
for (array_of_strings) |s, i| {
|
for (array_of_strings) |s, i| {
|
||||||
if (i == 0) assert(mem.eql(u8, s, "hello"));
|
if (i == 0) assert(mem.eql(u8, s, "hello"));
|
||||||
if (i == 1) assert(mem.eql(u8, s, "this"));
|
if (i == 1) assert(mem.eql(u8, s, "this"));
|
||||||
@ -61,7 +78,6 @@ test "nested arrays" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var s_array: [8]Sub = undefined;
|
var s_array: [8]Sub = undefined;
|
||||||
const Sub = struct {
|
const Sub = struct {
|
||||||
b: u8,
|
b: u8,
|
||||||
@ -70,7 +86,9 @@ const Str = struct {
|
|||||||
a: []Sub,
|
a: []Sub,
|
||||||
};
|
};
|
||||||
test "set global var array via slice embedded in struct" {
|
test "set global var array via slice embedded in struct" {
|
||||||
var s = Str { .a = s_array[0..]};
|
var s = Str {
|
||||||
|
.a = s_array[0..],
|
||||||
|
};
|
||||||
|
|
||||||
s.a[0].b = 1;
|
s.a[0].b = 1;
|
||||||
s.a[1].b = 2;
|
s.a[1].b = 2;
|
||||||
@ -82,7 +100,10 @@ test "set global var array via slice embedded in struct" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "array literal with specified size" {
|
test "array literal with specified size" {
|
||||||
var array = [2]u8{1, 2};
|
var array = [2]u8 {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
};
|
||||||
assert(array[0] == 1);
|
assert(array[0] == 1);
|
||||||
assert(array[1] == 2);
|
assert(array[1] == 2);
|
||||||
}
|
}
|
||||||
|
@ -10,5 +10,9 @@ fn testBitCast_i32_u32() void {
|
|||||||
assert(conv2(@maxValue(u32)) == -1);
|
assert(conv2(@maxValue(u32)) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conv(x: i32) u32 { return @bitCast(u32, x); }
|
fn conv(x: i32) u32 {
|
||||||
fn conv2(x: u32) i32 { return @bitCast(i32, x); }
|
return @bitCast(u32, x);
|
||||||
|
}
|
||||||
|
fn conv2(x: u32) i32 {
|
||||||
|
return @bitCast(i32, x);
|
||||||
|
}
|
||||||
|
@ -1,9 +1,20 @@
|
|||||||
const E = union(enum) { A: [9]u8, B: u64, };
|
const E = union(enum) {
|
||||||
const S = struct { x: u8, y: E, };
|
A: [9]u8,
|
||||||
|
B: u64,
|
||||||
|
};
|
||||||
|
const S = struct {
|
||||||
|
x: u8,
|
||||||
|
y: E,
|
||||||
|
};
|
||||||
|
|
||||||
const assert = @import("std").debug.assert;
|
const assert = @import("std").debug.assert;
|
||||||
|
|
||||||
test "bug 394 fixed" {
|
test "bug 394 fixed" {
|
||||||
const x = S { .x = 3, .y = E {.B = 1 } };
|
const x = S {
|
||||||
|
.x = 3,
|
||||||
|
.y = E {
|
||||||
|
.B = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
assert(x.x == 3);
|
assert(x.x == 3);
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,5 @@ test "function with &const parameter with type dereferenced by namespace" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn foo(x: &const other_file.Integer) void {
|
fn foo(x: &const other_file.Integer) void {
|
||||||
std.debug.assert(*x == 1234);
|
std.debug.assert(x.* == 1234);
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,15 @@ test "nullable if after an if in a switch prong of a switch with 2 prongs in an
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn foo(a: bool, b: bool) void {
|
fn foo(a: bool, b: bool) void {
|
||||||
var prefix_op = PrefixOp { .AddrOf = Value { .align_expr = 1234 } };
|
var prefix_op = PrefixOp {
|
||||||
if (a) {
|
.AddrOf = Value {
|
||||||
} else {
|
.align_expr = 1234,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (a) {} else {
|
||||||
switch (prefix_op) {
|
switch (prefix_op) {
|
||||||
PrefixOp.AddrOf => |addr_of_info| {
|
PrefixOp.AddrOf => |addr_of_info| {
|
||||||
if (b) { }
|
if (b) {}
|
||||||
if (addr_of_info.align_expr) |align_expr| {
|
if (addr_of_info.align_expr) |align_expr| {
|
||||||
assert(align_expr == 1234);
|
assert(align_expr == 1234);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
const CountBy = struct {
|
const CountBy = struct {
|
||||||
a: usize,
|
a: usize,
|
||||||
|
|
||||||
const One = CountBy {
|
const One = CountBy {
|
||||||
.a = 1,
|
.a = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn counter(self: &const CountBy) Counter {
|
pub fn counter(self: &const CountBy) Counter {
|
||||||
return Counter {
|
return Counter {
|
||||||
.i = 0,
|
.i = 0,
|
||||||
@ -14,7 +14,7 @@ const CountBy = struct {
|
|||||||
|
|
||||||
const Counter = struct {
|
const Counter = struct {
|
||||||
i: usize,
|
i: usize,
|
||||||
|
|
||||||
pub fn count(self: &Counter) bool {
|
pub fn count(self: &Counter) bool {
|
||||||
self.i += 1;
|
self.i += 1;
|
||||||
return self.i <= 10;
|
return self.i <= 10;
|
||||||
@ -24,8 +24,8 @@ const Counter = struct {
|
|||||||
fn constCount(comptime cb: &const CountBy, comptime unused: u32) void {
|
fn constCount(comptime cb: &const CountBy, comptime unused: u32) void {
|
||||||
comptime {
|
comptime {
|
||||||
var cnt = cb.counter();
|
var cnt = cb.counter();
|
||||||
if(cnt.i != 0) @compileError("Counter instance reused!");
|
if (cnt.i != 0) @compileError("Counter instance reused!");
|
||||||
while(cnt.count()){}
|
while (cnt.count()) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,7 @@ const ZigTable = struct {
|
|||||||
zero_case: fn(&Random, f64) f64,
|
zero_case: fn(&Random, f64) f64,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn(f64) f64,
|
fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn(f64) f64, comptime f_inv: fn(f64) f64, comptime zero_case: fn(&Random, f64) f64) ZigTable {
|
||||||
comptime f_inv: fn(f64) f64, comptime zero_case: fn(&Random, f64) f64) ZigTable {
|
|
||||||
var tables: ZigTable = undefined;
|
var tables: ZigTable = undefined;
|
||||||
|
|
||||||
tables.is_symmetric = is_symmetric;
|
tables.is_symmetric = is_symmetric;
|
||||||
@ -26,12 +25,12 @@ fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, co
|
|||||||
|
|
||||||
for (tables.x[2..256]) |*entry, i| {
|
for (tables.x[2..256]) |*entry, i| {
|
||||||
const last = tables.x[2 + i - 1];
|
const last = tables.x[2 + i - 1];
|
||||||
*entry = f_inv(v / last + f(last));
|
entry.* = f_inv(v / last + f(last));
|
||||||
}
|
}
|
||||||
tables.x[256] = 0;
|
tables.x[256] = 0;
|
||||||
|
|
||||||
for (tables.f[0..]) |*entry, i| {
|
for (tables.f[0..]) |*entry, i| {
|
||||||
*entry = f(tables.x[i]);
|
entry.* = f(tables.x[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tables;
|
return tables;
|
||||||
@ -40,9 +39,15 @@ fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, co
|
|||||||
const norm_r = 3.6541528853610088;
|
const norm_r = 3.6541528853610088;
|
||||||
const norm_v = 0.00492867323399;
|
const norm_v = 0.00492867323399;
|
||||||
|
|
||||||
fn norm_f(x: f64) f64 { return math.exp(-x * x / 2.0); }
|
fn norm_f(x: f64) f64 {
|
||||||
fn norm_f_inv(y: f64) f64 { return math.sqrt(-2.0 * math.ln(y)); }
|
return math.exp(-x * x / 2.0);
|
||||||
fn norm_zero_case(random: &Random, u: f64) f64 { return 0.0; }
|
}
|
||||||
|
fn norm_f_inv(y: f64) f64 {
|
||||||
|
return math.sqrt(-2.0 * math.ln(y));
|
||||||
|
}
|
||||||
|
fn norm_zero_case(random: &Random, u: f64) f64 {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
const NormalDist = blk: {
|
const NormalDist = blk: {
|
||||||
@setEvalBranchQuota(30000);
|
@setEvalBranchQuota(30000);
|
||||||
|
@ -14,10 +14,10 @@ test "integer literal to pointer cast" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "pointer reinterpret const float to int" {
|
test "pointer reinterpret const float to int" {
|
||||||
const float: f64 = 5.99999999999994648725e-01;
|
const float: f64 = 5.99999999999994648725e - 01;
|
||||||
const float_ptr = &float;
|
const float_ptr = &float;
|
||||||
const int_ptr = @ptrCast(&const i32, float_ptr);
|
const int_ptr = @ptrCast(&const i32, float_ptr);
|
||||||
const int_val = *int_ptr;
|
const int_val = int_ptr.*;
|
||||||
assert(int_val == 858993411);
|
assert(int_val == 858993411);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,25 +29,31 @@ test "implicitly cast a pointer to a const pointer of it" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn funcWithConstPtrPtr(x: &const &i32) void {
|
fn funcWithConstPtrPtr(x: &const &i32) void {
|
||||||
**x += 1;
|
x.*.* += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "implicitly cast a container to a const pointer of it" {
|
test "implicitly cast a container to a const pointer of it" {
|
||||||
const z = Struct(void) { .x = void{} };
|
const z = Struct(void) {
|
||||||
|
.x = void{},
|
||||||
|
};
|
||||||
assert(0 == @sizeOf(@typeOf(z)));
|
assert(0 == @sizeOf(@typeOf(z)));
|
||||||
assert(void{} == Struct(void).pointer(z).x);
|
assert(void{} == Struct(void).pointer(z).x);
|
||||||
assert(void{} == Struct(void).pointer(&z).x);
|
assert(void{} == Struct(void).pointer(&z).x);
|
||||||
assert(void{} == Struct(void).maybePointer(z).x);
|
assert(void{} == Struct(void).maybePointer(z).x);
|
||||||
assert(void{} == Struct(void).maybePointer(&z).x);
|
assert(void{} == Struct(void).maybePointer(&z).x);
|
||||||
assert(void{} == Struct(void).maybePointer(null).x);
|
assert(void{} == Struct(void).maybePointer(null).x);
|
||||||
const s = Struct(u8) { .x = 42 };
|
const s = Struct(u8) {
|
||||||
|
.x = 42,
|
||||||
|
};
|
||||||
assert(0 != @sizeOf(@typeOf(s)));
|
assert(0 != @sizeOf(@typeOf(s)));
|
||||||
assert(42 == Struct(u8).pointer(s).x);
|
assert(42 == Struct(u8).pointer(s).x);
|
||||||
assert(42 == Struct(u8).pointer(&s).x);
|
assert(42 == Struct(u8).pointer(&s).x);
|
||||||
assert(42 == Struct(u8).maybePointer(s).x);
|
assert(42 == Struct(u8).maybePointer(s).x);
|
||||||
assert(42 == Struct(u8).maybePointer(&s).x);
|
assert(42 == Struct(u8).maybePointer(&s).x);
|
||||||
assert(0 == Struct(u8).maybePointer(null).x);
|
assert(0 == Struct(u8).maybePointer(null).x);
|
||||||
const u = Union { .x = 42 };
|
const u = Union {
|
||||||
|
.x = 42,
|
||||||
|
};
|
||||||
assert(42 == Union.pointer(u).x);
|
assert(42 == Union.pointer(u).x);
|
||||||
assert(42 == Union.pointer(&u).x);
|
assert(42 == Union.pointer(&u).x);
|
||||||
assert(42 == Union.maybePointer(u).x);
|
assert(42 == Union.maybePointer(u).x);
|
||||||
@ -67,12 +73,14 @@ fn Struct(comptime T: type) type {
|
|||||||
x: T,
|
x: T,
|
||||||
|
|
||||||
fn pointer(self: &const Self) Self {
|
fn pointer(self: &const Self) Self {
|
||||||
return *self;
|
return self.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybePointer(self: ?&const Self) Self {
|
fn maybePointer(self: ?&const Self) Self {
|
||||||
const none = Self { .x = if (T == void) void{} else 0 };
|
const none = Self {
|
||||||
return *(self ?? &none);
|
.x = if (T == void) void{} else 0,
|
||||||
|
};
|
||||||
|
return (self ?? &none).*;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -81,12 +89,14 @@ const Union = union {
|
|||||||
x: u8,
|
x: u8,
|
||||||
|
|
||||||
fn pointer(self: &const Union) Union {
|
fn pointer(self: &const Union) Union {
|
||||||
return *self;
|
return self.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybePointer(self: ?&const Union) Union {
|
fn maybePointer(self: ?&const Union) Union {
|
||||||
const none = Union { .x = 0 };
|
const none = Union {
|
||||||
return *(self ?? &none);
|
.x = 0,
|
||||||
|
};
|
||||||
|
return (self ?? &none).*;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -95,11 +105,11 @@ const Enum = enum {
|
|||||||
Some,
|
Some,
|
||||||
|
|
||||||
fn pointer(self: &const Enum) Enum {
|
fn pointer(self: &const Enum) Enum {
|
||||||
return *self;
|
return self.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybePointer(self: ?&const Enum) Enum {
|
fn maybePointer(self: ?&const Enum) Enum {
|
||||||
return *(self ?? &Enum.None);
|
return (self ?? &Enum.None).*;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,19 +118,21 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {
|
|||||||
const Self = this;
|
const Self = this;
|
||||||
x: u8,
|
x: u8,
|
||||||
fn constConst(p: &const &const Self) u8 {
|
fn constConst(p: &const &const Self) u8 {
|
||||||
return (*p).x;
|
return (p.*).x;
|
||||||
}
|
}
|
||||||
fn maybeConstConst(p: ?&const &const Self) u8 {
|
fn maybeConstConst(p: ?&const &const Self) u8 {
|
||||||
return (*??p).x;
|
return (??p.*).x;
|
||||||
}
|
}
|
||||||
fn constConstConst(p: &const &const &const Self) u8 {
|
fn constConstConst(p: &const &const &const Self) u8 {
|
||||||
return (**p).x;
|
return (p.*.*).x;
|
||||||
}
|
}
|
||||||
fn maybeConstConstConst(p: ?&const &const &const Self) u8 {
|
fn maybeConstConstConst(p: ?&const &const &const Self) u8 {
|
||||||
return (**??p).x;
|
return (??p.*.*).x;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const s = S { .x = 42 };
|
const s = S {
|
||||||
|
.x = 42,
|
||||||
|
};
|
||||||
const p = &s;
|
const p = &s;
|
||||||
const q = &p;
|
const q = &p;
|
||||||
const r = &q;
|
const r = &q;
|
||||||
@ -154,7 +166,6 @@ fn boolToStr(b: bool) []const u8 {
|
|||||||
return if (b) "true" else "false";
|
return if (b) "true" else "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "peer resolve array and const slice" {
|
test "peer resolve array and const slice" {
|
||||||
testPeerResolveArrayConstSlice(true);
|
testPeerResolveArrayConstSlice(true);
|
||||||
comptime testPeerResolveArrayConstSlice(true);
|
comptime testPeerResolveArrayConstSlice(true);
|
||||||
@ -168,12 +179,12 @@ fn testPeerResolveArrayConstSlice(b: bool) void {
|
|||||||
|
|
||||||
test "integer literal to &const int" {
|
test "integer literal to &const int" {
|
||||||
const x: &const i32 = 3;
|
const x: &const i32 = 3;
|
||||||
assert(*x == 3);
|
assert(x.* == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "string literal to &const []const u8" {
|
test "string literal to &const []const u8" {
|
||||||
const x: &const []const u8 = "hello";
|
const x: &const []const u8 = "hello";
|
||||||
assert(mem.eql(u8, *x, "hello"));
|
assert(mem.eql(u8, x.*, "hello"));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "implicitly cast from T to error!?T" {
|
test "implicitly cast from T to error!?T" {
|
||||||
@ -191,7 +202,9 @@ fn castToMaybeTypeError(z: i32) void {
|
|||||||
const f = z;
|
const f = z;
|
||||||
const g: error!?i32 = f;
|
const g: error!?i32 = f;
|
||||||
|
|
||||||
const a = A{ .a = z };
|
const a = A {
|
||||||
|
.a = z,
|
||||||
|
};
|
||||||
const b: error!?A = a;
|
const b: error!?A = a;
|
||||||
assert((??(b catch unreachable)).a == 1);
|
assert((??(b catch unreachable)).a == 1);
|
||||||
}
|
}
|
||||||
@ -205,7 +218,6 @@ fn implicitIntLitToMaybe() void {
|
|||||||
const g: error!?i32 = 1;
|
const g: error!?i32 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "return null from fn() error!?&T" {
|
test "return null from fn() error!?&T" {
|
||||||
const a = returnNullFromMaybeTypeErrorRef();
|
const a = returnNullFromMaybeTypeErrorRef();
|
||||||
const b = returnNullLitFromMaybeTypeErrorRef();
|
const b = returnNullLitFromMaybeTypeErrorRef();
|
||||||
@ -235,7 +247,6 @@ fn peerTypeTAndMaybeT(c: bool, b: bool) ?usize {
|
|||||||
return usize(3);
|
return usize(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "peer type resolution: [0]u8 and []const u8" {
|
test "peer type resolution: [0]u8 and []const u8" {
|
||||||
assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
|
assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
|
||||||
assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
|
assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
|
||||||
@ -246,7 +257,7 @@ test "peer type resolution: [0]u8 and []const u8" {
|
|||||||
}
|
}
|
||||||
fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
|
fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
|
||||||
if (a) {
|
if (a) {
|
||||||
return []const u8 {};
|
return []const u8{};
|
||||||
}
|
}
|
||||||
|
|
||||||
return slice[0..1];
|
return slice[0..1];
|
||||||
@ -261,7 +272,6 @@ fn castToMaybeSlice() ?[]const u8 {
|
|||||||
return "hi";
|
return "hi";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "implicitly cast from [0]T to error![]T" {
|
test "implicitly cast from [0]T to error![]T" {
|
||||||
testCastZeroArrayToErrSliceMut();
|
testCastZeroArrayToErrSliceMut();
|
||||||
comptime testCastZeroArrayToErrSliceMut();
|
comptime testCastZeroArrayToErrSliceMut();
|
||||||
@ -329,7 +339,6 @@ fn foo(args: ...) void {
|
|||||||
assert(@typeOf(args[0]) == &const [5]u8);
|
assert(@typeOf(args[0]) == &const [5]u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "peer type resolution: error and [N]T" {
|
test "peer type resolution: error and [N]T" {
|
||||||
// TODO: implicit error!T to error!U where T can implicitly cast to U
|
// TODO: implicit error!T to error!U where T can implicitly cast to U
|
||||||
//assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
|
//assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
|
||||||
@ -378,7 +387,12 @@ fn cast128Float(x: u128) f128 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "const slice widen cast" {
|
test "const slice widen cast" {
|
||||||
const bytes align(4) = []u8{0x12, 0x12, 0x12, 0x12};
|
const bytes align(4) = []u8 {
|
||||||
|
0x12,
|
||||||
|
0x12,
|
||||||
|
0x12,
|
||||||
|
0x12,
|
||||||
|
};
|
||||||
|
|
||||||
const u32_value = ([]const u32)(bytes[0..])[0];
|
const u32_value = ([]const u32)(bytes[0..])[0];
|
||||||
assert(u32_value == 0x12121212);
|
assert(u32_value == 0x12121212);
|
||||||
|
@ -36,7 +36,7 @@ async fn testAsyncSeq() void {
|
|||||||
suspend;
|
suspend;
|
||||||
seq('d');
|
seq('d');
|
||||||
}
|
}
|
||||||
var points = []u8{0} ** "abcdefg".len;
|
var points = []u8 {0} ** "abcdefg".len;
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
|
|
||||||
fn seq(c: u8) void {
|
fn seq(c: u8) void {
|
||||||
@ -94,7 +94,7 @@ async fn await_another() i32 {
|
|||||||
return 1234;
|
return 1234;
|
||||||
}
|
}
|
||||||
|
|
||||||
var await_points = []u8{0} ** "abcdefghi".len;
|
var await_points = []u8 {0} ** "abcdefghi".len;
|
||||||
var await_seq_index: usize = 0;
|
var await_seq_index: usize = 0;
|
||||||
|
|
||||||
fn await_seq(c: u8) void {
|
fn await_seq(c: u8) void {
|
||||||
@ -102,7 +102,6 @@ fn await_seq(c: u8) void {
|
|||||||
await_seq_index += 1;
|
await_seq_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var early_final_result: i32 = 0;
|
var early_final_result: i32 = 0;
|
||||||
|
|
||||||
test "coroutine await early return" {
|
test "coroutine await early return" {
|
||||||
@ -126,7 +125,7 @@ async fn early_another() i32 {
|
|||||||
return 1234;
|
return 1234;
|
||||||
}
|
}
|
||||||
|
|
||||||
var early_points = []u8{0} ** "abcdef".len;
|
var early_points = []u8 {0} ** "abcdef".len;
|
||||||
var early_seq_index: usize = 0;
|
var early_seq_index: usize = 0;
|
||||||
|
|
||||||
fn early_seq(c: u8) void {
|
fn early_seq(c: u8) void {
|
||||||
@ -175,8 +174,8 @@ test "async fn pointer in a struct field" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
|
async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
|
||||||
defer *y += 2;
|
defer y.* += 2;
|
||||||
*y += 1;
|
y.* += 1;
|
||||||
suspend;
|
suspend;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +204,8 @@ test "error return trace across suspend points - async return" {
|
|||||||
cancel p2;
|
cancel p2;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nonFailing() promise->error!void {
|
// TODO https://github.com/zig-lang/zig/issues/760
|
||||||
|
fn nonFailing() (promise->error!void) {
|
||||||
return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
|
return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +238,7 @@ async fn testBreakFromSuspend(my_result: &i32) void {
|
|||||||
s: suspend |p| {
|
s: suspend |p| {
|
||||||
break :s;
|
break :s;
|
||||||
}
|
}
|
||||||
*my_result += 1;
|
my_result.* += 1;
|
||||||
suspend;
|
suspend;
|
||||||
*my_result += 1;
|
my_result.* += 1;
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,18 @@ var index: usize = undefined;
|
|||||||
|
|
||||||
fn runSomeErrorDefers(x: bool) !bool {
|
fn runSomeErrorDefers(x: bool) !bool {
|
||||||
index = 0;
|
index = 0;
|
||||||
defer {result[index] = 'a'; index += 1;}
|
defer {
|
||||||
errdefer {result[index] = 'b'; index += 1;}
|
result[index] = 'a';
|
||||||
defer {result[index] = 'c'; index += 1;}
|
index += 1;
|
||||||
|
}
|
||||||
|
errdefer {
|
||||||
|
result[index] = 'b';
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
defer {
|
||||||
|
result[index] = 'c';
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
return if (x) x else error.FalseNotAllowed;
|
return if (x) x else error.FalseNotAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,15 @@ const assert = @import("std").debug.assert;
|
|||||||
const mem = @import("std").mem;
|
const mem = @import("std").mem;
|
||||||
|
|
||||||
test "enum type" {
|
test "enum type" {
|
||||||
const foo1 = Foo{ .One = 13};
|
const foo1 = Foo {
|
||||||
const foo2 = Foo{. Two = Point { .x = 1234, .y = 5678, }};
|
.One = 13,
|
||||||
|
};
|
||||||
|
const foo2 = Foo {
|
||||||
|
.Two = Point {
|
||||||
|
.x = 1234,
|
||||||
|
.y = 5678,
|
||||||
|
},
|
||||||
|
};
|
||||||
const bar = Bar.B;
|
const bar = Bar.B;
|
||||||
|
|
||||||
assert(bar == Bar.B);
|
assert(bar == Bar.B);
|
||||||
@ -41,26 +48,31 @@ const Bar = enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn returnAnInt(x: i32) Foo {
|
fn returnAnInt(x: i32) Foo {
|
||||||
return Foo { .One = x };
|
return Foo {
|
||||||
|
.One = x,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "constant enum with payload" {
|
test "constant enum with payload" {
|
||||||
var empty = AnEnumWithPayload {.Empty = {}};
|
var empty = AnEnumWithPayload {
|
||||||
var full = AnEnumWithPayload {.Full = 13};
|
.Empty = {},
|
||||||
|
};
|
||||||
|
var full = AnEnumWithPayload {
|
||||||
|
.Full = 13,
|
||||||
|
};
|
||||||
shouldBeEmpty(empty);
|
shouldBeEmpty(empty);
|
||||||
shouldBeNotEmpty(full);
|
shouldBeNotEmpty(full);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shouldBeEmpty(x: &const AnEnumWithPayload) void {
|
fn shouldBeEmpty(x: &const AnEnumWithPayload) void {
|
||||||
switch (*x) {
|
switch (x.*) {
|
||||||
AnEnumWithPayload.Empty => {},
|
AnEnumWithPayload.Empty => {},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shouldBeNotEmpty(x: &const AnEnumWithPayload) void {
|
fn shouldBeNotEmpty(x: &const AnEnumWithPayload) void {
|
||||||
switch (*x) {
|
switch (x.*) {
|
||||||
AnEnumWithPayload.Empty => unreachable,
|
AnEnumWithPayload.Empty => unreachable,
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@ -71,8 +83,6 @@ const AnEnumWithPayload = union(enum) {
|
|||||||
Full: i32,
|
Full: i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const Number = enum {
|
const Number = enum {
|
||||||
Zero,
|
Zero,
|
||||||
One,
|
One,
|
||||||
@ -93,7 +103,6 @@ fn shouldEqual(n: Number, expected: u3) void {
|
|||||||
assert(u3(n) == expected);
|
assert(u3(n) == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "int to enum" {
|
test "int to enum" {
|
||||||
testIntToEnumEval(3);
|
testIntToEnumEval(3);
|
||||||
}
|
}
|
||||||
@ -108,7 +117,6 @@ const IntToEnumNumber = enum {
|
|||||||
Four,
|
Four,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
test "@tagName" {
|
test "@tagName" {
|
||||||
assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
|
assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
|
||||||
comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
|
comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
|
||||||
@ -124,7 +132,6 @@ const BareNumber = enum {
|
|||||||
Three,
|
Three,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
test "enum alignment" {
|
test "enum alignment" {
|
||||||
comptime {
|
comptime {
|
||||||
assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
|
assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
|
||||||
@ -137,47 +144,529 @@ const AlignTestEnum = union(enum) {
|
|||||||
B: u64,
|
B: u64,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ValueCount1 = enum { I0 };
|
const ValueCount1 = enum {
|
||||||
const ValueCount2 = enum { I0, I1 };
|
I0,
|
||||||
|
};
|
||||||
|
const ValueCount2 = enum {
|
||||||
|
I0,
|
||||||
|
I1,
|
||||||
|
};
|
||||||
const ValueCount256 = enum {
|
const ValueCount256 = enum {
|
||||||
I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,
|
I0,
|
||||||
I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,
|
I1,
|
||||||
I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,
|
I2,
|
||||||
I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,
|
I3,
|
||||||
I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,
|
I4,
|
||||||
I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,
|
I5,
|
||||||
I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,
|
I6,
|
||||||
I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,
|
I7,
|
||||||
I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,
|
I8,
|
||||||
I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,
|
I9,
|
||||||
I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,
|
I10,
|
||||||
I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,
|
I11,
|
||||||
I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,
|
I12,
|
||||||
I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,
|
I13,
|
||||||
I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,
|
I14,
|
||||||
I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,
|
I15,
|
||||||
I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,
|
I16,
|
||||||
I250, I251, I252, I253, I254, I255
|
I17,
|
||||||
|
I18,
|
||||||
|
I19,
|
||||||
|
I20,
|
||||||
|
I21,
|
||||||
|
I22,
|
||||||
|
I23,
|
||||||
|
I24,
|
||||||
|
I25,
|
||||||
|
I26,
|
||||||
|
I27,
|
||||||
|
I28,
|
||||||
|
I29,
|
||||||
|
I30,
|
||||||
|
I31,
|
||||||
|
I32,
|
||||||
|
I33,
|
||||||
|
I34,
|
||||||
|
I35,
|
||||||
|
I36,
|
||||||
|
I37,
|
||||||
|
I38,
|
||||||
|
I39,
|
||||||
|
I40,
|
||||||
|
I41,
|
||||||
|
I42,
|
||||||
|
I43,
|
||||||
|
I44,
|
||||||
|
I45,
|
||||||
|
I46,
|
||||||
|
I47,
|
||||||
|
I48,
|
||||||
|
I49,
|
||||||
|
I50,
|
||||||
|
I51,
|
||||||
|
I52,
|
||||||
|
I53,
|
||||||
|
I54,
|
||||||
|
I55,
|
||||||
|
I56,
|
||||||
|
I57,
|
||||||
|
I58,
|
||||||
|
I59,
|
||||||
|
I60,
|
||||||
|
I61,
|
||||||
|
I62,
|
||||||
|
I63,
|
||||||
|
I64,
|
||||||
|
I65,
|
||||||
|
I66,
|
||||||
|
I67,
|
||||||
|
I68,
|
||||||
|
I69,
|
||||||
|
I70,
|
||||||
|
I71,
|
||||||
|
I72,
|
||||||
|
I73,
|
||||||
|
I74,
|
||||||
|
I75,
|
||||||
|
I76,
|
||||||
|
I77,
|
||||||
|
I78,
|
||||||
|
I79,
|
||||||
|
I80,
|
||||||
|
I81,
|
||||||
|
I82,
|
||||||
|
I83,
|
||||||
|
I84,
|
||||||
|
I85,
|
||||||
|
I86,
|
||||||
|
I87,
|
||||||
|
I88,
|
||||||
|
I89,
|
||||||
|
I90,
|
||||||
|
I91,
|
||||||
|
I92,
|
||||||
|
I93,
|
||||||
|
I94,
|
||||||
|
I95,
|
||||||
|
I96,
|
||||||
|
I97,
|
||||||
|
I98,
|
||||||
|
I99,
|
||||||
|
I100,
|
||||||
|
I101,
|
||||||
|
I102,
|
||||||
|
I103,
|
||||||
|
I104,
|
||||||
|
I105,
|
||||||
|
I106,
|
||||||
|
I107,
|
||||||
|
I108,
|
||||||
|
I109,
|
||||||
|
I110,
|
||||||
|
I111,
|
||||||
|
I112,
|
||||||
|
I113,
|
||||||
|
I114,
|
||||||
|
I115,
|
||||||
|
I116,
|
||||||
|
I117,
|
||||||
|
I118,
|
||||||
|
I119,
|
||||||
|
I120,
|
||||||
|
I121,
|
||||||
|
I122,
|
||||||
|
I123,
|
||||||
|
I124,
|
||||||
|
I125,
|
||||||
|
I126,
|
||||||
|
I127,
|
||||||
|
I128,
|
||||||
|
I129,
|
||||||
|
I130,
|
||||||
|
I131,
|
||||||
|
I132,
|
||||||
|
I133,
|
||||||
|
I134,
|
||||||
|
I135,
|
||||||
|
I136,
|
||||||
|
I137,
|
||||||
|
I138,
|
||||||
|
I139,
|
||||||
|
I140,
|
||||||
|
I141,
|
||||||
|
I142,
|
||||||
|
I143,
|
||||||
|
I144,
|
||||||
|
I145,
|
||||||
|
I146,
|
||||||
|
I147,
|
||||||
|
I148,
|
||||||
|
I149,
|
||||||
|
I150,
|
||||||
|
I151,
|
||||||
|
I152,
|
||||||
|
I153,
|
||||||
|
I154,
|
||||||
|
I155,
|
||||||
|
I156,
|
||||||
|
I157,
|
||||||
|
I158,
|
||||||
|
I159,
|
||||||
|
I160,
|
||||||
|
I161,
|
||||||
|
I162,
|
||||||
|
I163,
|
||||||
|
I164,
|
||||||
|
I165,
|
||||||
|
I166,
|
||||||
|
I167,
|
||||||
|
I168,
|
||||||
|
I169,
|
||||||
|
I170,
|
||||||
|
I171,
|
||||||
|
I172,
|
||||||
|
I173,
|
||||||
|
I174,
|
||||||
|
I175,
|
||||||
|
I176,
|
||||||
|
I177,
|
||||||
|
I178,
|
||||||
|
I179,
|
||||||
|
I180,
|
||||||
|
I181,
|
||||||
|
I182,
|
||||||
|
I183,
|
||||||
|
I184,
|
||||||
|
I185,
|
||||||
|
I186,
|
||||||
|
I187,
|
||||||
|
I188,
|
||||||
|
I189,
|
||||||
|
I190,
|
||||||
|
I191,
|
||||||
|
I192,
|
||||||
|
I193,
|
||||||
|
I194,
|
||||||
|
I195,
|
||||||
|
I196,
|
||||||
|
I197,
|
||||||
|
I198,
|
||||||
|
I199,
|
||||||
|
I200,
|
||||||
|
I201,
|
||||||
|
I202,
|
||||||
|
I203,
|
||||||
|
I204,
|
||||||
|
I205,
|
||||||
|
I206,
|
||||||
|
I207,
|
||||||
|
I208,
|
||||||
|
I209,
|
||||||
|
I210,
|
||||||
|
I211,
|
||||||
|
I212,
|
||||||
|
I213,
|
||||||
|
I214,
|
||||||
|
I215,
|
||||||
|
I216,
|
||||||
|
I217,
|
||||||
|
I218,
|
||||||
|
I219,
|
||||||
|
I220,
|
||||||
|
I221,
|
||||||
|
I222,
|
||||||
|
I223,
|
||||||
|
I224,
|
||||||
|
I225,
|
||||||
|
I226,
|
||||||
|
I227,
|
||||||
|
I228,
|
||||||
|
I229,
|
||||||
|
I230,
|
||||||
|
I231,
|
||||||
|
I232,
|
||||||
|
I233,
|
||||||
|
I234,
|
||||||
|
I235,
|
||||||
|
I236,
|
||||||
|
I237,
|
||||||
|
I238,
|
||||||
|
I239,
|
||||||
|
I240,
|
||||||
|
I241,
|
||||||
|
I242,
|
||||||
|
I243,
|
||||||
|
I244,
|
||||||
|
I245,
|
||||||
|
I246,
|
||||||
|
I247,
|
||||||
|
I248,
|
||||||
|
I249,
|
||||||
|
I250,
|
||||||
|
I251,
|
||||||
|
I252,
|
||||||
|
I253,
|
||||||
|
I254,
|
||||||
|
I255,
|
||||||
};
|
};
|
||||||
const ValueCount257 = enum {
|
const ValueCount257 = enum {
|
||||||
I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,
|
I0,
|
||||||
I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,
|
I1,
|
||||||
I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,
|
I2,
|
||||||
I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,
|
I3,
|
||||||
I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,
|
I4,
|
||||||
I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,
|
I5,
|
||||||
I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,
|
I6,
|
||||||
I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,
|
I7,
|
||||||
I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,
|
I8,
|
||||||
I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,
|
I9,
|
||||||
I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,
|
I10,
|
||||||
I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,
|
I11,
|
||||||
I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,
|
I12,
|
||||||
I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,
|
I13,
|
||||||
I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,
|
I14,
|
||||||
I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,
|
I15,
|
||||||
I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,
|
I16,
|
||||||
I250, I251, I252, I253, I254, I255, I256
|
I17,
|
||||||
|
I18,
|
||||||
|
I19,
|
||||||
|
I20,
|
||||||
|
I21,
|
||||||
|
I22,
|
||||||
|
I23,
|
||||||
|
I24,
|
||||||
|
I25,
|
||||||
|
I26,
|
||||||
|
I27,
|
||||||
|
I28,
|
||||||
|
I29,
|
||||||
|
I30,
|
||||||
|
I31,
|
||||||
|
I32,
|
||||||
|
I33,
|
||||||
|
I34,
|
||||||
|
I35,
|
||||||
|
I36,
|
||||||
|
I37,
|
||||||
|
I38,
|
||||||
|
I39,
|
||||||
|
I40,
|
||||||
|
I41,
|
||||||
|
I42,
|
||||||
|
I43,
|
||||||
|
I44,
|
||||||
|
I45,
|
||||||
|
I46,
|
||||||
|
I47,
|
||||||
|
I48,
|
||||||
|
I49,
|
||||||
|
I50,
|
||||||
|
I51,
|
||||||
|
I52,
|
||||||
|
I53,
|
||||||
|
I54,
|
||||||
|
I55,
|
||||||
|
I56,
|
||||||
|
I57,
|
||||||
|
I58,
|
||||||
|
I59,
|
||||||
|
I60,
|
||||||
|
I61,
|
||||||
|
I62,
|
||||||
|
I63,
|
||||||
|
I64,
|
||||||
|
I65,
|
||||||
|
I66,
|
||||||
|
I67,
|
||||||
|
I68,
|
||||||
|
I69,
|
||||||
|
I70,
|
||||||
|
I71,
|
||||||
|
I72,
|
||||||
|
I73,
|
||||||
|
I74,
|
||||||
|
I75,
|
||||||
|
I76,
|
||||||
|
I77,
|
||||||
|
I78,
|
||||||
|
I79,
|
||||||
|
I80,
|
||||||
|
I81,
|
||||||
|
I82,
|
||||||
|
I83,
|
||||||
|
I84,
|
||||||
|
I85,
|
||||||
|
I86,
|
||||||
|
I87,
|
||||||
|
I88,
|
||||||
|
I89,
|
||||||
|
I90,
|
||||||
|
I91,
|
||||||
|
I92,
|
||||||
|
I93,
|
||||||
|
I94,
|
||||||
|
I95,
|
||||||
|
I96,
|
||||||
|
I97,
|
||||||
|
I98,
|
||||||
|
I99,
|
||||||
|
I100,
|
||||||
|
I101,
|
||||||
|
I102,
|
||||||
|
I103,
|
||||||
|
I104,
|
||||||
|
I105,
|
||||||
|
I106,
|
||||||
|
I107,
|
||||||
|
I108,
|
||||||
|
I109,
|
||||||
|
I110,
|
||||||
|
I111,
|
||||||
|
I112,
|
||||||
|
I113,
|
||||||
|
I114,
|
||||||
|
I115,
|
||||||
|
I116,
|
||||||
|
I117,
|
||||||
|
I118,
|
||||||
|
I119,
|
||||||
|
I120,
|
||||||
|
I121,
|
||||||
|
I122,
|
||||||
|
I123,
|
||||||
|
I124,
|
||||||
|
I125,
|
||||||
|
I126,
|
||||||
|
I127,
|
||||||
|
I128,
|
||||||
|
I129,
|
||||||
|
I130,
|
||||||
|
I131,
|
||||||
|
I132,
|
||||||
|
I133,
|
||||||
|
I134,
|
||||||
|
I135,
|
||||||
|
I136,
|
||||||
|
I137,
|
||||||
|
I138,
|
||||||
|
I139,
|
||||||
|
I140,
|
||||||
|
I141,
|
||||||
|
I142,
|
||||||
|
I143,
|
||||||
|
I144,
|
||||||
|
I145,
|
||||||
|
I146,
|
||||||
|
I147,
|
||||||
|
I148,
|
||||||
|
I149,
|
||||||
|
I150,
|
||||||
|
I151,
|
||||||
|
I152,
|
||||||
|
I153,
|
||||||
|
I154,
|
||||||
|
I155,
|
||||||
|
I156,
|
||||||
|
I157,
|
||||||
|
I158,
|
||||||
|
I159,
|
||||||
|
I160,
|
||||||
|
I161,
|
||||||
|
I162,
|
||||||
|
I163,
|
||||||
|
I164,
|
||||||
|
I165,
|
||||||
|
I166,
|
||||||
|
I167,
|
||||||
|
I168,
|
||||||
|
I169,
|
||||||
|
I170,
|
||||||
|
I171,
|
||||||
|
I172,
|
||||||
|
I173,
|
||||||
|
I174,
|
||||||
|
I175,
|
||||||
|
I176,
|
||||||
|
I177,
|
||||||
|
I178,
|
||||||
|
I179,
|
||||||
|
I180,
|
||||||
|
I181,
|
||||||
|
I182,
|
||||||
|
I183,
|
||||||
|
I184,
|
||||||
|
I185,
|
||||||
|
I186,
|
||||||
|
I187,
|
||||||
|
I188,
|
||||||
|
I189,
|
||||||
|
I190,
|
||||||
|
I191,
|
||||||
|
I192,
|
||||||
|
I193,
|
||||||
|
I194,
|
||||||
|
I195,
|
||||||
|
I196,
|
||||||
|
I197,
|
||||||
|
I198,
|
||||||
|
I199,
|
||||||
|
I200,
|
||||||
|
I201,
|
||||||
|
I202,
|
||||||
|
I203,
|
||||||
|
I204,
|
||||||
|
I205,
|
||||||
|
I206,
|
||||||
|
I207,
|
||||||
|
I208,
|
||||||
|
I209,
|
||||||
|
I210,
|
||||||
|
I211,
|
||||||
|
I212,
|
||||||
|
I213,
|
||||||
|
I214,
|
||||||
|
I215,
|
||||||
|
I216,
|
||||||
|
I217,
|
||||||
|
I218,
|
||||||
|
I219,
|
||||||
|
I220,
|
||||||
|
I221,
|
||||||
|
I222,
|
||||||
|
I223,
|
||||||
|
I224,
|
||||||
|
I225,
|
||||||
|
I226,
|
||||||
|
I227,
|
||||||
|
I228,
|
||||||
|
I229,
|
||||||
|
I230,
|
||||||
|
I231,
|
||||||
|
I232,
|
||||||
|
I233,
|
||||||
|
I234,
|
||||||
|
I235,
|
||||||
|
I236,
|
||||||
|
I237,
|
||||||
|
I238,
|
||||||
|
I239,
|
||||||
|
I240,
|
||||||
|
I241,
|
||||||
|
I242,
|
||||||
|
I243,
|
||||||
|
I244,
|
||||||
|
I245,
|
||||||
|
I246,
|
||||||
|
I247,
|
||||||
|
I248,
|
||||||
|
I249,
|
||||||
|
I250,
|
||||||
|
I251,
|
||||||
|
I252,
|
||||||
|
I253,
|
||||||
|
I254,
|
||||||
|
I255,
|
||||||
|
I256,
|
||||||
};
|
};
|
||||||
|
|
||||||
test "enum sizes" {
|
test "enum sizes" {
|
||||||
@ -189,11 +678,11 @@ test "enum sizes" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Small2 = enum (u2) {
|
const Small2 = enum(u2) {
|
||||||
One,
|
One,
|
||||||
Two,
|
Two,
|
||||||
};
|
};
|
||||||
const Small = enum (u2) {
|
const Small = enum(u2) {
|
||||||
One,
|
One,
|
||||||
Two,
|
Two,
|
||||||
Three,
|
Three,
|
||||||
@ -213,8 +702,7 @@ test "set enum tag type" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const A = enum(u3) {
|
||||||
const A = enum (u3) {
|
|
||||||
One,
|
One,
|
||||||
Two,
|
Two,
|
||||||
Three,
|
Three,
|
||||||
@ -225,7 +713,7 @@ const A = enum (u3) {
|
|||||||
Four2,
|
Four2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const B = enum (u3) {
|
const B = enum(u3) {
|
||||||
One3,
|
One3,
|
||||||
Two3,
|
Two3,
|
||||||
Three3,
|
Three3,
|
||||||
@ -236,7 +724,7 @@ const B = enum (u3) {
|
|||||||
Four23,
|
Four23,
|
||||||
};
|
};
|
||||||
|
|
||||||
const C = enum (u2) {
|
const C = enum(u2) {
|
||||||
One4,
|
One4,
|
||||||
Two4,
|
Two4,
|
||||||
Three4,
|
Three4,
|
||||||
@ -389,6 +877,8 @@ test "enum with tag values don't require parens" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "enum with 1 field but explicit tag type should still have the tag type" {
|
test "enum with 1 field but explicit tag type should still have the tag type" {
|
||||||
const Enum = enum(u8) { B = 2 };
|
const Enum = enum(u8) {
|
||||||
|
B = 2,
|
||||||
|
};
|
||||||
comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
|
comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ const ET = union(enum) {
|
|||||||
UINT: u32,
|
UINT: u32,
|
||||||
|
|
||||||
pub fn print(a: &const ET, buf: []u8) error!usize {
|
pub fn print(a: &const ET, buf: []u8) error!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),
|
||||||
};
|
};
|
||||||
@ -15,8 +15,12 @@ const ET = union(enum) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test "enum with members" {
|
test "enum with members" {
|
||||||
const a = ET { .SINT = -42 };
|
const a = ET {
|
||||||
const b = ET { .UINT = 42 };
|
.SINT = -42,
|
||||||
|
};
|
||||||
|
const b = ET {
|
||||||
|
.UINT = 42,
|
||||||
|
};
|
||||||
var buf: [20]u8 = undefined;
|
var buf: [20]u8 = undefined;
|
||||||
|
|
||||||
assert((a.print(buf[0..]) catch unreachable) == 3);
|
assert((a.print(buf[0..]) catch unreachable) == 3);
|
||||||
|
@ -30,14 +30,12 @@ test "@errorName" {
|
|||||||
assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
|
assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "error values" {
|
test "error values" {
|
||||||
const a = i32(error.err1);
|
const a = i32(error.err1);
|
||||||
const b = i32(error.err2);
|
const b = i32(error.err2);
|
||||||
assert(a != b);
|
assert(a != b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "redefinition of error values allowed" {
|
test "redefinition of error values allowed" {
|
||||||
shouldBeNotEqual(error.AnError, error.SecondError);
|
shouldBeNotEqual(error.AnError, error.SecondError);
|
||||||
}
|
}
|
||||||
@ -45,7 +43,6 @@ fn shouldBeNotEqual(a: error, b: error) void {
|
|||||||
if (a == b) unreachable;
|
if (a == b) unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "error binary operator" {
|
test "error binary operator" {
|
||||||
const a = errBinaryOperatorG(true) catch 3;
|
const a = errBinaryOperatorG(true) catch 3;
|
||||||
const b = errBinaryOperatorG(false) catch 3;
|
const b = errBinaryOperatorG(false) catch 3;
|
||||||
@ -56,20 +53,20 @@ fn errBinaryOperatorG(x: bool) error!isize {
|
|||||||
return if (x) error.ItBroke else isize(10);
|
return if (x) error.ItBroke else isize(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "unwrap simple value from error" {
|
test "unwrap simple value from error" {
|
||||||
const i = unwrapSimpleValueFromErrorDo() catch unreachable;
|
const i = unwrapSimpleValueFromErrorDo() catch unreachable;
|
||||||
assert(i == 13);
|
assert(i == 13);
|
||||||
}
|
}
|
||||||
fn unwrapSimpleValueFromErrorDo() error!isize { return 13; }
|
fn unwrapSimpleValueFromErrorDo() error!isize {
|
||||||
|
return 13;
|
||||||
|
}
|
||||||
|
|
||||||
test "error return in assignment" {
|
test "error return in assignment" {
|
||||||
doErrReturnInAssignment() catch unreachable;
|
doErrReturnInAssignment() catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn doErrReturnInAssignment() error!void {
|
fn doErrReturnInAssignment() error!void {
|
||||||
var x : i32 = undefined;
|
var x: i32 = undefined;
|
||||||
x = try makeANonErr();
|
x = try makeANonErr();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +92,10 @@ test "error set type " {
|
|||||||
comptime testErrorSetType();
|
comptime testErrorSetType();
|
||||||
}
|
}
|
||||||
|
|
||||||
const MyErrSet = error {OutOfMemory, FileNotFound};
|
const MyErrSet = error {
|
||||||
|
OutOfMemory,
|
||||||
|
FileNotFound,
|
||||||
|
};
|
||||||
|
|
||||||
fn testErrorSetType() void {
|
fn testErrorSetType() void {
|
||||||
assert(@memberCount(MyErrSet) == 2);
|
assert(@memberCount(MyErrSet) == 2);
|
||||||
@ -109,14 +109,19 @@ fn testErrorSetType() void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "explicit error set cast" {
|
test "explicit error set cast" {
|
||||||
testExplicitErrorSetCast(Set1.A);
|
testExplicitErrorSetCast(Set1.A);
|
||||||
comptime testExplicitErrorSetCast(Set1.A);
|
comptime testExplicitErrorSetCast(Set1.A);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Set1 = error{A, B};
|
const Set1 = error {
|
||||||
const Set2 = error{A, C};
|
A,
|
||||||
|
B,
|
||||||
|
};
|
||||||
|
const Set2 = error {
|
||||||
|
A,
|
||||||
|
C,
|
||||||
|
};
|
||||||
|
|
||||||
fn testExplicitErrorSetCast(set1: Set1) void {
|
fn testExplicitErrorSetCast(set1: Set1) void {
|
||||||
var x = Set2(set1);
|
var x = Set2(set1);
|
||||||
@ -129,7 +134,8 @@ test "comptime test error for empty error set" {
|
|||||||
comptime testComptimeTestErrorEmptySet(1234);
|
comptime testComptimeTestErrorEmptySet(1234);
|
||||||
}
|
}
|
||||||
|
|
||||||
const EmptyErrorSet = error {};
|
const EmptyErrorSet = error {
|
||||||
|
};
|
||||||
|
|
||||||
fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
|
fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
|
||||||
if (x) |v| assert(v == 1234) else |err| @compileError("bad");
|
if (x) |v| assert(v == 1234) else |err| @compileError("bad");
|
||||||
@ -145,7 +151,9 @@ test "comptime err to int of error set with only 1 possible value" {
|
|||||||
testErrToIntWithOnePossibleValue(error.A, u32(error.A));
|
testErrToIntWithOnePossibleValue(error.A, u32(error.A));
|
||||||
comptime testErrToIntWithOnePossibleValue(error.A, u32(error.A));
|
comptime testErrToIntWithOnePossibleValue(error.A, u32(error.A));
|
||||||
}
|
}
|
||||||
fn testErrToIntWithOnePossibleValue(x: error{A}, comptime value: u32) void {
|
fn testErrToIntWithOnePossibleValue(x: error {
|
||||||
|
A,
|
||||||
|
}, comptime value: u32) void {
|
||||||
if (u32(x) != value) {
|
if (u32(x) != value) {
|
||||||
@compileError("bad");
|
@compileError("bad");
|
||||||
}
|
}
|
||||||
@ -176,7 +184,6 @@ fn quux_1() !i32 {
|
|||||||
return error.C;
|
return error.C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "error: fn returning empty error set can be passed as fn returning any error" {
|
test "error: fn returning empty error set can be passed as fn returning any error" {
|
||||||
entry();
|
entry();
|
||||||
comptime entry();
|
comptime entry();
|
||||||
@ -186,24 +193,24 @@ fn entry() void {
|
|||||||
foo2(bar2);
|
foo2(bar2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo2(f: fn()error!void) void {
|
fn foo2(f: fn() error!void) void {
|
||||||
const x = f();
|
const x = f();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bar2() (error{}!void) { }
|
fn bar2() (error {
|
||||||
|
}!void) {}
|
||||||
|
|
||||||
test "error: Zero sized error set returned with value payload crash" {
|
test "error: Zero sized error set returned with value payload crash" {
|
||||||
_ = foo3(0);
|
_ = foo3(0);
|
||||||
_ = comptime foo3(0);
|
_ = comptime foo3(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Error = error{};
|
const Error = error {
|
||||||
|
};
|
||||||
fn foo3(b: usize) Error!usize {
|
fn foo3(b: usize) Error!usize {
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "error: Infer error set from literals" {
|
test "error: Infer error set from literals" {
|
||||||
_ = nullLiteral("n") catch |err| handleErrors(err);
|
_ = nullLiteral("n") catch |err| handleErrors(err);
|
||||||
_ = floatLiteral("n") catch |err| handleErrors(err);
|
_ = floatLiteral("n") catch |err| handleErrors(err);
|
||||||
@ -215,29 +222,26 @@ test "error: Infer error set from literals" {
|
|||||||
|
|
||||||
fn handleErrors(err: var) noreturn {
|
fn handleErrors(err: var) noreturn {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
error.T => {}
|
error.T => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nullLiteral(str: []const u8) !?i64 {
|
fn nullLiteral(str: []const u8) !?i64 {
|
||||||
if (str[0] == 'n')
|
if (str[0] == 'n') return null;
|
||||||
return null;
|
|
||||||
|
|
||||||
return error.T;
|
return error.T;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn floatLiteral(str: []const u8) !?f64 {
|
fn floatLiteral(str: []const u8) !?f64 {
|
||||||
if (str[0] == 'n')
|
if (str[0] == 'n') return 1.0;
|
||||||
return 1.0;
|
|
||||||
|
|
||||||
return error.T;
|
return error.T;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intLiteral(str: []const u8) !?i64 {
|
fn intLiteral(str: []const u8) !?i64 {
|
||||||
if (str[0] == 'n')
|
if (str[0] == 'n') return 1;
|
||||||
return 1;
|
|
||||||
|
|
||||||
return error.T;
|
return error.T;
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,6 @@ fn fibonacci(x: i32) i32 {
|
|||||||
return fibonacci(x - 1) + fibonacci(x - 2);
|
return fibonacci(x - 1) + fibonacci(x - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn unwrapAndAddOne(blah: ?i32) i32 {
|
fn unwrapAndAddOne(blah: ?i32) i32 {
|
||||||
return ??blah + 1;
|
return ??blah + 1;
|
||||||
}
|
}
|
||||||
@ -40,13 +38,13 @@ test "inline variable gets result of const if" {
|
|||||||
assert(gimme1or2(false) == 2);
|
assert(gimme1or2(false) == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "static function evaluation" {
|
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 { return 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" {
|
||||||
assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
|
assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
|
||||||
@ -64,9 +62,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test "statically initialized list" {
|
test "statically initialized list" {
|
||||||
assert(static_point_list[0].x == 1);
|
assert(static_point_list[0].x == 1);
|
||||||
assert(static_point_list[0].y == 2);
|
assert(static_point_list[0].y == 2);
|
||||||
@ -77,7 +72,10 @@ const Point = struct {
|
|||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
};
|
};
|
||||||
const static_point_list = []Point { makePoint(1, 2), makePoint(3, 4) };
|
const static_point_list = []Point {
|
||||||
|
makePoint(1, 2),
|
||||||
|
makePoint(3, 4),
|
||||||
|
};
|
||||||
fn makePoint(x: i32, y: i32) Point {
|
fn makePoint(x: i32, y: i32) Point {
|
||||||
return Point {
|
return Point {
|
||||||
.x = x,
|
.x = x,
|
||||||
@ -85,7 +83,6 @@ fn makePoint(x: i32, y: i32) Point {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "static eval list init" {
|
test "static eval list init" {
|
||||||
assert(static_vec3.data[2] == 1.0);
|
assert(static_vec3.data[2] == 1.0);
|
||||||
assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
|
assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
|
||||||
@ -96,17 +93,19 @@ pub const Vec3 = struct {
|
|||||||
};
|
};
|
||||||
pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
|
pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
|
||||||
return Vec3 {
|
return Vec3 {
|
||||||
.data = []f32 { x, y, z, },
|
.data = []f32 {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
z,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "constant expressions" {
|
test "constant expressions" {
|
||||||
var array : [array_size]u8 = undefined;
|
var array: [array_size]u8 = undefined;
|
||||||
assert(@sizeOf(@typeOf(array)) == 20);
|
assert(@sizeOf(@typeOf(array)) == 20);
|
||||||
}
|
}
|
||||||
const array_size : u8 = 20;
|
const array_size: u8 = 20;
|
||||||
|
|
||||||
|
|
||||||
test "constant struct with negation" {
|
test "constant struct with negation" {
|
||||||
assert(vertices[0].x == -0.6);
|
assert(vertices[0].x == -0.6);
|
||||||
@ -119,12 +118,29 @@ const Vertex = struct {
|
|||||||
b: f32,
|
b: f32,
|
||||||
};
|
};
|
||||||
const vertices = []Vertex {
|
const vertices = []Vertex {
|
||||||
Vertex { .x = -0.6, .y = -0.4, .r = 1.0, .g = 0.0, .b = 0.0 },
|
Vertex {
|
||||||
Vertex { .x = 0.6, .y = -0.4, .r = 0.0, .g = 1.0, .b = 0.0 },
|
.x = -0.6,
|
||||||
Vertex { .x = 0.0, .y = 0.6, .r = 0.0, .g = 0.0, .b = 1.0 },
|
.y = -0.4,
|
||||||
|
.r = 1.0,
|
||||||
|
.g = 0.0,
|
||||||
|
.b = 0.0,
|
||||||
|
},
|
||||||
|
Vertex {
|
||||||
|
.x = 0.6,
|
||||||
|
.y = -0.4,
|
||||||
|
.r = 0.0,
|
||||||
|
.g = 1.0,
|
||||||
|
.b = 0.0,
|
||||||
|
},
|
||||||
|
Vertex {
|
||||||
|
.x = 0.0,
|
||||||
|
.y = 0.6,
|
||||||
|
.r = 0.0,
|
||||||
|
.g = 0.0,
|
||||||
|
.b = 1.0,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
test "statically initialized struct" {
|
test "statically initialized struct" {
|
||||||
st_init_str_foo.x += 1;
|
st_init_str_foo.x += 1;
|
||||||
assert(st_init_str_foo.x == 14);
|
assert(st_init_str_foo.x == 14);
|
||||||
@ -133,15 +149,21 @@ const StInitStrFoo = struct {
|
|||||||
x: i32,
|
x: i32,
|
||||||
y: bool,
|
y: bool,
|
||||||
};
|
};
|
||||||
var st_init_str_foo = StInitStrFoo { .x = 13, .y = true, };
|
var st_init_str_foo = StInitStrFoo {
|
||||||
|
.x = 13,
|
||||||
|
.y = true,
|
||||||
|
};
|
||||||
|
|
||||||
test "statically initalized array literal" {
|
test "statically initalized array literal" {
|
||||||
const y : [4]u8 = st_init_arr_lit_x;
|
const y: [4]u8 = st_init_arr_lit_x;
|
||||||
assert(y[3] == 4);
|
assert(y[3] == 4);
|
||||||
}
|
}
|
||||||
const st_init_arr_lit_x = []u8{1,2,3,4};
|
const st_init_arr_lit_x = []u8 {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
};
|
||||||
|
|
||||||
test "const slice" {
|
test "const slice" {
|
||||||
comptime {
|
comptime {
|
||||||
@ -198,14 +220,29 @@ const CmdFn = struct {
|
|||||||
func: fn(i32) i32,
|
func: fn(i32) i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
const cmd_fns = []CmdFn{
|
const cmd_fns = []CmdFn {
|
||||||
CmdFn {.name = "one", .func = one},
|
CmdFn {
|
||||||
CmdFn {.name = "two", .func = two},
|
.name = "one",
|
||||||
CmdFn {.name = "three", .func = three},
|
.func = one,
|
||||||
|
},
|
||||||
|
CmdFn {
|
||||||
|
.name = "two",
|
||||||
|
.func = two,
|
||||||
|
},
|
||||||
|
CmdFn {
|
||||||
|
.name = "three",
|
||||||
|
.func = three,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
fn one(value: i32) i32 { return value + 1; }
|
fn one(value: i32) i32 {
|
||||||
fn two(value: i32) i32 { return value + 2; }
|
return value + 1;
|
||||||
fn three(value: i32) i32 { return value + 3; }
|
}
|
||||||
|
fn two(value: i32) i32 {
|
||||||
|
return value + 2;
|
||||||
|
}
|
||||||
|
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;
|
||||||
@ -229,7 +266,7 @@ test "eval @setRuntimeSafety at compile-time" {
|
|||||||
assert(result == 1234);
|
assert(result == 1234);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fnWithSetRuntimeSafety() i32{
|
fn fnWithSetRuntimeSafety() i32 {
|
||||||
@setRuntimeSafety(true);
|
@setRuntimeSafety(true);
|
||||||
return 1234;
|
return 1234;
|
||||||
}
|
}
|
||||||
@ -244,7 +281,6 @@ fn fnWithFloatMode() f32 {
|
|||||||
return 1234.0;
|
return 1234.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const SimpleStruct = struct {
|
const SimpleStruct = struct {
|
||||||
field: i32,
|
field: i32,
|
||||||
|
|
||||||
@ -253,7 +289,9 @@ const SimpleStruct = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var simple_struct = SimpleStruct{ .field = 1234, };
|
var simple_struct = SimpleStruct {
|
||||||
|
.field = 1234,
|
||||||
|
};
|
||||||
|
|
||||||
const bound_fn = simple_struct.method;
|
const bound_fn = simple_struct.method;
|
||||||
|
|
||||||
@ -261,8 +299,6 @@ test "call method on bound fn referring to var instance" {
|
|||||||
assert(bound_fn() == 1237);
|
assert(bound_fn() == 1237);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test "ptr to local array argument at comptime" {
|
test "ptr to local array argument at comptime" {
|
||||||
comptime {
|
comptime {
|
||||||
var bytes: [10]u8 = undefined;
|
var bytes: [10]u8 = undefined;
|
||||||
@ -277,7 +313,6 @@ fn modifySomeBytes(bytes: []u8) void {
|
|||||||
bytes[9] = 'b';
|
bytes[9] = 'b';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "comparisons 0 <= uint and 0 > uint should be comptime" {
|
test "comparisons 0 <= uint and 0 > uint should be comptime" {
|
||||||
testCompTimeUIntComparisons(1234);
|
testCompTimeUIntComparisons(1234);
|
||||||
}
|
}
|
||||||
@ -296,8 +331,6 @@ fn testCompTimeUIntComparisons(x: u32) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test "const ptr to variable data changes at runtime" {
|
test "const ptr to variable data changes at runtime" {
|
||||||
assert(foo_ref.name[0] == 'a');
|
assert(foo_ref.name[0] == 'a');
|
||||||
foo_ref.name = "b";
|
foo_ref.name = "b";
|
||||||
@ -308,11 +341,11 @@ const Foo = struct {
|
|||||||
name: []const u8,
|
name: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
var foo_contents = Foo { .name = "a", };
|
var foo_contents = Foo {
|
||||||
|
.name = "a",
|
||||||
|
};
|
||||||
const foo_ref = &foo_contents;
|
const foo_ref = &foo_contents;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test "create global array with for loop" {
|
test "create global array with for loop" {
|
||||||
assert(global_array[5] == 5 * 5);
|
assert(global_array[5] == 5 * 5);
|
||||||
assert(global_array[9] == 9 * 9);
|
assert(global_array[9] == 9 * 9);
|
||||||
@ -321,7 +354,7 @@ test "create global array with for loop" {
|
|||||||
const global_array = x: {
|
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;
|
||||||
}
|
}
|
||||||
break :x result;
|
break :x result;
|
||||||
};
|
};
|
||||||
@ -379,7 +412,7 @@ test "f128 at compile time is lossy" {
|
|||||||
|
|
||||||
pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
|
pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
|
||||||
return struct {
|
return struct {
|
||||||
pub const Node = struct { };
|
pub const Node = struct {};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,10 +434,10 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {
|
|||||||
comptime var i: usize = 0;
|
comptime var i: usize = 0;
|
||||||
inline while (i < 4) : (i += 1) {
|
inline while (i < 4) : (i += 1) {
|
||||||
s[i] = 0;
|
s[i] = 0;
|
||||||
s[i] |= u32(b[i*4+0]) << 24;
|
s[i] |= u32(b[i * 4 + 0]) << 24;
|
||||||
s[i] |= u32(b[i*4+1]) << 16;
|
s[i] |= u32(b[i * 4 + 1]) << 16;
|
||||||
s[i] |= u32(b[i*4+2]) << 8;
|
s[i] |= u32(b[i * 4 + 2]) << 8;
|
||||||
s[i] |= u32(b[i*4+3]) << 0;
|
s[i] |= u32(b[i * 4 + 3]) << 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,7 +446,7 @@ test "binary math operator in partially inlined function" {
|
|||||||
var b: [16]u8 = undefined;
|
var b: [16]u8 = undefined;
|
||||||
|
|
||||||
for (b) |*r, i|
|
for (b) |*r, i|
|
||||||
*r = u8(i + 1);
|
r.* = u8(i + 1);
|
||||||
|
|
||||||
copyWithPartialInline(s[0..], b[0..]);
|
copyWithPartialInline(s[0..], b[0..]);
|
||||||
assert(s[0] == 0x1020304);
|
assert(s[0] == 0x1020304);
|
||||||
@ -422,7 +455,6 @@ test "binary math operator in partially inlined function" {
|
|||||||
assert(s[3] == 0xd0e0f10);
|
assert(s[3] == 0xd0e0f10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "comptime function with the same args is memoized" {
|
test "comptime function with the same args is memoized" {
|
||||||
comptime {
|
comptime {
|
||||||
assert(MakeType(i32) == MakeType(i32));
|
assert(MakeType(i32) == MakeType(i32));
|
||||||
@ -447,12 +479,12 @@ test "comptime function with mutable pointer is not memoized" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn increment(value: &i32) void {
|
fn increment(value: &i32) void {
|
||||||
*value += 1;
|
value.* += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generateTable(comptime T: type) [1010]T {
|
fn generateTable(comptime T: type) [1010]T {
|
||||||
var res : [1010]T = undefined;
|
var res: [1010]T = undefined;
|
||||||
var i : usize = 0;
|
var i: usize = 0;
|
||||||
while (i < 1010) : (i += 1) {
|
while (i < 1010) : (i += 1) {
|
||||||
res[i] = T(i);
|
res[i] = T(i);
|
||||||
}
|
}
|
||||||
@ -496,9 +528,10 @@ const SingleFieldStruct = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
test "const ptr to comptime mutable data is not memoized" {
|
test "const ptr to comptime mutable data is not memoized" {
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
var foo = SingleFieldStruct {.x = 1};
|
var foo = SingleFieldStruct {
|
||||||
|
.x = 1,
|
||||||
|
};
|
||||||
assert(foo.read_x() == 1);
|
assert(foo.read_x() == 1);
|
||||||
foo.x = 2;
|
foo.x = 2;
|
||||||
assert(foo.read_x() == 2);
|
assert(foo.read_x() == 2);
|
||||||
|
@ -7,7 +7,6 @@ fn testParamsAdd(a: i32, b: i32) i32 {
|
|||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "local variables" {
|
test "local variables" {
|
||||||
testLocVars(2);
|
testLocVars(2);
|
||||||
}
|
}
|
||||||
@ -16,7 +15,6 @@ fn testLocVars(b: i32) void {
|
|||||||
if (a + b != 3) unreachable;
|
if (a + b != 3) unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "void parameters" {
|
test "void parameters" {
|
||||||
voidFun(1, void{}, 2, {});
|
voidFun(1, void{}, 2, {});
|
||||||
}
|
}
|
||||||
@ -27,9 +25,8 @@ fn voidFun(a: i32, b: void, c: i32, d: void) void {
|
|||||||
return vv;
|
return vv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "mutable local variables" {
|
test "mutable local variables" {
|
||||||
var zero : i32 = 0;
|
var zero: i32 = 0;
|
||||||
assert(zero == 0);
|
assert(zero == 0);
|
||||||
|
|
||||||
var i = i32(0);
|
var i = i32(0);
|
||||||
@ -41,7 +38,7 @@ test "mutable local variables" {
|
|||||||
|
|
||||||
test "separate block scopes" {
|
test "separate block scopes" {
|
||||||
{
|
{
|
||||||
const no_conflict : i32 = 5;
|
const no_conflict: i32 = 5;
|
||||||
assert(no_conflict == 5);
|
assert(no_conflict == 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +53,7 @@ test "call function with empty string" {
|
|||||||
acceptsString("");
|
acceptsString("");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn acceptsString(foo: []u8) void { }
|
fn acceptsString(foo: []u8) void {}
|
||||||
|
|
||||||
|
|
||||||
fn @"weird function name"() i32 {
|
fn @"weird function name"() i32 {
|
||||||
return 1234;
|
return 1234;
|
||||||
@ -70,31 +66,43 @@ test "implicit cast function unreachable return" {
|
|||||||
wantsFnWithVoid(fnWithUnreachable);
|
wantsFnWithVoid(fnWithUnreachable);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wantsFnWithVoid(f: fn() void) void { }
|
fn wantsFnWithVoid(f: fn() void) void {}
|
||||||
|
|
||||||
fn fnWithUnreachable() noreturn {
|
fn fnWithUnreachable() noreturn {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "function pointers" {
|
test "function pointers" {
|
||||||
const fns = []@typeOf(fn1) { fn1, fn2, fn3, fn4, };
|
const fns = []@typeOf(fn1) {
|
||||||
|
fn1,
|
||||||
|
fn2,
|
||||||
|
fn3,
|
||||||
|
fn4,
|
||||||
|
};
|
||||||
for (fns) |f, i| {
|
for (fns) |f, i| {
|
||||||
assert(f() == u32(i) + 5);
|
assert(f() == u32(i) + 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fn1() u32 {return 5;}
|
fn fn1() u32 {
|
||||||
fn fn2() u32 {return 6;}
|
return 5;
|
||||||
fn fn3() u32 {return 7;}
|
}
|
||||||
fn fn4() u32 {return 8;}
|
fn fn2() u32 {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
fn fn3() u32 {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
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 { return a + b; }
|
fn add(a: i32, b: i32) i32 {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
test "number literal as an argument" {
|
test "number literal as an argument" {
|
||||||
numberLiteralArg(3);
|
numberLiteralArg(3);
|
||||||
@ -110,4 +118,4 @@ test "assign inline fn to const variable" {
|
|||||||
a();
|
a();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn inlineFn() void { }
|
inline fn inlineFn() void {}
|
||||||
|
@ -3,8 +3,14 @@ const assert = std.debug.assert;
|
|||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
test "continue in for loop" {
|
test "continue in for loop" {
|
||||||
const array = []i32 {1, 2, 3, 4, 5};
|
const array = []i32 {
|
||||||
var sum : i32 = 0;
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
};
|
||||||
|
var sum: i32 = 0;
|
||||||
for (array) |x| {
|
for (array) |x| {
|
||||||
sum += x;
|
sum += x;
|
||||||
if (x < 3) {
|
if (x < 3) {
|
||||||
@ -24,17 +30,39 @@ test "for loop with pointer elem var" {
|
|||||||
}
|
}
|
||||||
fn mangleString(s: []u8) void {
|
fn mangleString(s: []u8) void {
|
||||||
for (s) |*c| {
|
for (s) |*c| {
|
||||||
*c += 1;
|
c.* += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "basic for loop" {
|
test "basic for loop" {
|
||||||
const expected_result = []u8{9, 8, 7, 6, 0, 1, 2, 3, 9, 8, 7, 6, 0, 1, 2, 3 };
|
const expected_result = []u8 {
|
||||||
|
9,
|
||||||
|
8,
|
||||||
|
7,
|
||||||
|
6,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
9,
|
||||||
|
8,
|
||||||
|
7,
|
||||||
|
6,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
};
|
||||||
|
|
||||||
var buffer: [expected_result.len]u8 = undefined;
|
var buffer: [expected_result.len]u8 = undefined;
|
||||||
var buf_index: usize = 0;
|
var buf_index: usize = 0;
|
||||||
|
|
||||||
const array = []u8 {9, 8, 7, 6};
|
const array = []u8 {
|
||||||
|
9,
|
||||||
|
8,
|
||||||
|
7,
|
||||||
|
6,
|
||||||
|
};
|
||||||
for (array) |item| {
|
for (array) |item| {
|
||||||
buffer[buf_index] = item;
|
buffer[buf_index] = item;
|
||||||
buf_index += 1;
|
buf_index += 1;
|
||||||
@ -65,7 +93,8 @@ fn testBreakOuter() void {
|
|||||||
var array = "aoeu";
|
var array = "aoeu";
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
outer: for (array) |_| {
|
outer: for (array) |_| {
|
||||||
for (array) |_2| { // TODO shouldn't get error for redeclaring "_"
|
// TODO shouldn't get error for redeclaring "_"
|
||||||
|
for (array) |_2| {
|
||||||
count += 1;
|
count += 1;
|
||||||
break :outer;
|
break :outer;
|
||||||
}
|
}
|
||||||
@ -82,7 +111,8 @@ fn testContinueOuter() void {
|
|||||||
var array = "aoeu";
|
var array = "aoeu";
|
||||||
var counter: usize = 0;
|
var counter: usize = 0;
|
||||||
outer: for (array) |_| {
|
outer: for (array) |_| {
|
||||||
for (array) |_2| { // TODO shouldn't get error for redeclaring "_"
|
// TODO shouldn't get error for redeclaring "_"
|
||||||
|
for (array) |_2| {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
continue :outer;
|
continue :outer;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ test "fn with comptime args" {
|
|||||||
assert(sameButWithFloats(0.43, 0.49) == 0.49);
|
assert(sameButWithFloats(0.43, 0.49) == 0.49);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "var params" {
|
test "var params" {
|
||||||
assert(max_i32(12, 34) == 34);
|
assert(max_i32(12, 34) == 34);
|
||||||
assert(max_f64(1.2, 3.4) == 3.4);
|
assert(max_f64(1.2, 3.4) == 3.4);
|
||||||
@ -60,7 +59,6 @@ fn max_f64(a: f64, b: f64) f64 {
|
|||||||
return max_var(a, b);
|
return max_var(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn List(comptime T: type) type {
|
pub fn List(comptime T: type) type {
|
||||||
return SmallList(T, 8);
|
return SmallList(T, 8);
|
||||||
}
|
}
|
||||||
@ -82,10 +80,15 @@ test "function with return type type" {
|
|||||||
assert(list2.prealloc_items.len == 8);
|
assert(list2.prealloc_items.len == 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "generic struct" {
|
test "generic struct" {
|
||||||
var a1 = GenNode(i32) {.value = 13, .next = null,};
|
var a1 = GenNode(i32) {
|
||||||
var b1 = GenNode(bool) {.value = true, .next = null,};
|
.value = 13,
|
||||||
|
.next = null,
|
||||||
|
};
|
||||||
|
var b1 = GenNode(bool) {
|
||||||
|
.value = true,
|
||||||
|
.next = null,
|
||||||
|
};
|
||||||
assert(a1.value == 13);
|
assert(a1.value == 13);
|
||||||
assert(a1.value == a1.getVal());
|
assert(a1.value == a1.getVal());
|
||||||
assert(b1.getVal());
|
assert(b1.getVal());
|
||||||
@ -94,7 +97,9 @@ fn GenNode(comptime T: type) type {
|
|||||||
return struct {
|
return struct {
|
||||||
value: T,
|
value: T,
|
||||||
next: ?&GenNode(T),
|
next: ?&GenNode(T),
|
||||||
fn getVal(n: &const GenNode(T)) T { return n.value; }
|
fn getVal(n: &const GenNode(T)) T {
|
||||||
|
return n.value;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +112,6 @@ fn GenericDataThing(comptime count: isize) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "use generic param in generic param" {
|
test "use generic param in generic param" {
|
||||||
assert(aGenericFn(i32, 3, 4) == 7);
|
assert(aGenericFn(i32, 3, 4) == 7);
|
||||||
}
|
}
|
||||||
@ -115,21 +119,31 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
|
|||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "generic fn with implicit cast" {
|
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 {
|
||||||
|
return ??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 {
|
||||||
return 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 {
|
||||||
|
return arg;
|
||||||
fn foo1(arg: var) bool { return arg; }
|
}
|
||||||
fn foo2(arg: var) bool { return !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));
|
||||||
|
@ -23,7 +23,6 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "else if expression" {
|
test "else if expression" {
|
||||||
assert(elseIfExpressionF(1) == 1);
|
assert(elseIfExpressionF(1) == 1);
|
||||||
}
|
}
|
||||||
|
@ -1 +1,3 @@
|
|||||||
pub fn foo() i32 { return 1234; }
|
pub fn foo() i32 {
|
||||||
|
return 1234;
|
||||||
|
}
|
||||||
|
@ -11,7 +11,9 @@ fn foo(id: u64) !i32 {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getErrInt() error!i32 { return 0; }
|
fn getErrInt() error!i32 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
test "ir block deps" {
|
test "ir block deps" {
|
||||||
assert((foo(1) catch unreachable) == 0);
|
assert((foo(1) catch unreachable) == 0);
|
||||||
|
@ -28,25 +28,12 @@ fn testDivision() void {
|
|||||||
assert(divTrunc(f32, -5.0, 3.0) == -1.0);
|
assert(divTrunc(f32, -5.0, 3.0) == -1.0);
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
assert(
|
assert(1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600);
|
||||||
1194735857077236777412821811143690633098347576 %
|
assert(@rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600);
|
||||||
508740759824825164163191790951174292733114988 ==
|
assert(1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2);
|
||||||
177254337427586449086438229241342047632117600);
|
assert(@divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2);
|
||||||
assert(@rem(-1194735857077236777412821811143690633098347576,
|
assert(@divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2);
|
||||||
508740759824825164163191790951174292733114988) ==
|
assert(@divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2);
|
||||||
-177254337427586449086438229241342047632117600);
|
|
||||||
assert(1194735857077236777412821811143690633098347576 /
|
|
||||||
508740759824825164163191790951174292733114988 ==
|
|
||||||
2);
|
|
||||||
assert(@divTrunc(-1194735857077236777412821811143690633098347576,
|
|
||||||
508740759824825164163191790951174292733114988) ==
|
|
||||||
-2);
|
|
||||||
assert(@divTrunc(1194735857077236777412821811143690633098347576,
|
|
||||||
-508740759824825164163191790951174292733114988) ==
|
|
||||||
-2);
|
|
||||||
assert(@divTrunc(-1194735857077236777412821811143690633098347576,
|
|
||||||
-508740759824825164163191790951174292733114988) ==
|
|
||||||
2);
|
|
||||||
assert(4126227191251978491697987544882340798050766755606969681711 % 10 == 1);
|
assert(4126227191251978491697987544882340798050766755606969681711 % 10 == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,18 +101,28 @@ fn ctz(x: var) usize {
|
|||||||
|
|
||||||
test "assignment operators" {
|
test "assignment operators" {
|
||||||
var i: u32 = 0;
|
var i: u32 = 0;
|
||||||
i += 5; assert(i == 5);
|
i += 5;
|
||||||
i -= 2; assert(i == 3);
|
assert(i == 5);
|
||||||
i *= 20; assert(i == 60);
|
i -= 2;
|
||||||
i /= 3; assert(i == 20);
|
assert(i == 3);
|
||||||
i %= 11; assert(i == 9);
|
i *= 20;
|
||||||
i <<= 1; assert(i == 18);
|
assert(i == 60);
|
||||||
i >>= 2; assert(i == 4);
|
i /= 3;
|
||||||
|
assert(i == 20);
|
||||||
|
i %= 11;
|
||||||
|
assert(i == 9);
|
||||||
|
i <<= 1;
|
||||||
|
assert(i == 18);
|
||||||
|
i >>= 2;
|
||||||
|
assert(i == 4);
|
||||||
i = 6;
|
i = 6;
|
||||||
i &= 5; assert(i == 4);
|
i &= 5;
|
||||||
i ^= 6; assert(i == 2);
|
assert(i == 4);
|
||||||
|
i ^= 6;
|
||||||
|
assert(i == 2);
|
||||||
i = 6;
|
i = 6;
|
||||||
i |= 3; assert(i == 7);
|
i |= 3;
|
||||||
|
assert(i == 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "three expr in a row" {
|
test "three expr in a row" {
|
||||||
@ -138,7 +135,7 @@ fn testThreeExprInARow(f: bool, t: bool) void {
|
|||||||
assertFalse(1 | 2 | 4 != 7);
|
assertFalse(1 | 2 | 4 != 7);
|
||||||
assertFalse(3 ^ 6 ^ 8 != 13);
|
assertFalse(3 ^ 6 ^ 8 != 13);
|
||||||
assertFalse(7 & 14 & 28 != 4);
|
assertFalse(7 & 14 & 28 != 4);
|
||||||
assertFalse(9 << 1 << 2 != 9 << 3);
|
assertFalse(9 << 1 << 2 != 9 << 3);
|
||||||
assertFalse(90 >> 1 >> 2 != 90 >> 3);
|
assertFalse(90 >> 1 >> 2 != 90 >> 3);
|
||||||
assertFalse(100 - 1 + 1000 != 1099);
|
assertFalse(100 - 1 + 1000 != 1099);
|
||||||
assertFalse(5 * 4 / 2 % 3 != 1);
|
assertFalse(5 * 4 / 2 % 3 != 1);
|
||||||
@ -150,7 +147,6 @@ fn assertFalse(b: bool) void {
|
|||||||
assert(!b);
|
assert(!b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "const number literal" {
|
test "const number literal" {
|
||||||
const one = 1;
|
const one = 1;
|
||||||
const eleven = ten + one;
|
const eleven = ten + one;
|
||||||
@ -159,8 +155,6 @@ test "const number literal" {
|
|||||||
}
|
}
|
||||||
const ten = 10;
|
const ten = 10;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test "unsigned wrapping" {
|
test "unsigned wrapping" {
|
||||||
testUnsignedWrappingEval(@maxValue(u32));
|
testUnsignedWrappingEval(@maxValue(u32));
|
||||||
comptime testUnsignedWrappingEval(@maxValue(u32));
|
comptime testUnsignedWrappingEval(@maxValue(u32));
|
||||||
@ -214,8 +208,12 @@ const DivResult = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test "binary not" {
|
test "binary not" {
|
||||||
assert(comptime x: {break :x ~u16(0b1010101010101010) == 0b0101010101010101;});
|
assert(comptime x: {
|
||||||
assert(comptime x: {break :x ~u64(2147483647) == 18446744071562067968;});
|
break :x ~u16(0b1010101010101010) == 0b0101010101010101;
|
||||||
|
});
|
||||||
|
assert(comptime x: {
|
||||||
|
break :x ~u64(2147483647) == 18446744071562067968;
|
||||||
|
});
|
||||||
testBinaryNot(0b1010101010101010);
|
testBinaryNot(0b1010101010101010);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,27 +317,15 @@ fn testShrExact(x: u8) void {
|
|||||||
|
|
||||||
test "big number addition" {
|
test "big number addition" {
|
||||||
comptime {
|
comptime {
|
||||||
assert(
|
assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
|
||||||
35361831660712422535336160538497375248 +
|
assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
|
||||||
101752735581729509668353361206450473702 ==
|
|
||||||
137114567242441932203689521744947848950);
|
|
||||||
assert(
|
|
||||||
594491908217841670578297176641415611445982232488944558774612 +
|
|
||||||
390603545391089362063884922208143568023166603618446395589768 ==
|
|
||||||
985095453608931032642182098849559179469148836107390954364380);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "big number multiplication" {
|
test "big number multiplication" {
|
||||||
comptime {
|
comptime {
|
||||||
assert(
|
assert(45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567);
|
||||||
45960427431263824329884196484953148229 *
|
assert(594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016);
|
||||||
128339149605334697009938835852565949723 ==
|
|
||||||
5898522172026096622534201617172456926982464453350084962781392314016180490567);
|
|
||||||
assert(
|
|
||||||
594491908217841670578297176641415611445982232488944558774612 *
|
|
||||||
390603545391089362063884922208143568023166603618446395589768 ==
|
|
||||||
232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +366,9 @@ test "f128" {
|
|||||||
comptime test_f128();
|
comptime test_f128();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_f128(x: f128) f128 { return x; }
|
fn make_f128(x: f128) f128 {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
fn test_f128() void {
|
fn test_f128() void {
|
||||||
assert(@sizeOf(f128) == 16);
|
assert(@sizeOf(f128) == 16);
|
||||||
|
@ -4,6 +4,7 @@ const cstr = @import("std").cstr;
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
// normal comment
|
// normal comment
|
||||||
|
|
||||||
/// this is a documentation comment
|
/// this is a documentation comment
|
||||||
/// doc comment line 2
|
/// doc comment line 2
|
||||||
fn emptyFunctionWithComments() void {}
|
fn emptyFunctionWithComments() void {}
|
||||||
@ -16,8 +17,7 @@ comptime {
|
|||||||
@export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
|
@export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn disabledExternFn() void {
|
extern fn disabledExternFn() void {}
|
||||||
}
|
|
||||||
|
|
||||||
test "call disabled extern fn" {
|
test "call disabled extern fn" {
|
||||||
disabledExternFn();
|
disabledExternFn();
|
||||||
@ -110,17 +110,29 @@ fn testShortCircuit(f: bool, t: bool) void {
|
|||||||
var hit_3 = f;
|
var hit_3 = f;
|
||||||
var hit_4 = f;
|
var hit_4 = f;
|
||||||
|
|
||||||
if (t or x: {assert(f); break :x f;}) {
|
if (t or x: {
|
||||||
|
assert(f);
|
||||||
|
break :x f;
|
||||||
|
}) {
|
||||||
hit_1 = t;
|
hit_1 = t;
|
||||||
}
|
}
|
||||||
if (f or x: { hit_2 = t; break :x f; }) {
|
if (f or x: {
|
||||||
|
hit_2 = t;
|
||||||
|
break :x f;
|
||||||
|
}) {
|
||||||
assert(f);
|
assert(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t and x: { hit_3 = t; break :x f; }) {
|
if (t and x: {
|
||||||
|
hit_3 = t;
|
||||||
|
break :x f;
|
||||||
|
}) {
|
||||||
assert(f);
|
assert(f);
|
||||||
}
|
}
|
||||||
if (f and x: {assert(f); break :x f;}) {
|
if (f and x: {
|
||||||
|
assert(f);
|
||||||
|
break :x f;
|
||||||
|
}) {
|
||||||
assert(f);
|
assert(f);
|
||||||
} else {
|
} else {
|
||||||
hit_4 = t;
|
hit_4 = t;
|
||||||
@ -146,8 +158,8 @@ test "return string from function" {
|
|||||||
assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
|
assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const g1 : i32 = 1233 + 1;
|
const g1: i32 = 1233 + 1;
|
||||||
var g2 : i32 = 0;
|
var g2: i32 = 0;
|
||||||
|
|
||||||
test "global variables" {
|
test "global variables" {
|
||||||
assert(g2 == 0);
|
assert(g2 == 0);
|
||||||
@ -155,10 +167,9 @@ test "global variables" {
|
|||||||
assert(g2 == 1234);
|
assert(g2 == 1234);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "memcpy and memset intrinsics" {
|
test "memcpy and memset intrinsics" {
|
||||||
var foo : [20]u8 = undefined;
|
var foo: [20]u8 = undefined;
|
||||||
var bar : [20]u8 = undefined;
|
var bar: [20]u8 = undefined;
|
||||||
|
|
||||||
@memset(&foo[0], 'A', foo.len);
|
@memset(&foo[0], 'A', foo.len);
|
||||||
@memcpy(&bar[0], &foo[0], bar.len);
|
@memcpy(&bar[0], &foo[0], bar.len);
|
||||||
@ -167,12 +178,14 @@ test "memcpy and memset intrinsics" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "builtin static eval" {
|
test "builtin static eval" {
|
||||||
const x : i32 = comptime x: {break :x 1 + 2 + 3;};
|
const x: i32 = comptime x: {
|
||||||
|
break :x 1 + 2 + 3;
|
||||||
|
};
|
||||||
assert(x == comptime 6);
|
assert(x == comptime 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "slicing" {
|
test "slicing" {
|
||||||
var array : [20]i32 = undefined;
|
var array: [20]i32 = undefined;
|
||||||
|
|
||||||
array[5] = 1234;
|
array[5] = 1234;
|
||||||
|
|
||||||
@ -187,15 +200,15 @@ test "slicing" {
|
|||||||
if (slice_rest.len != 10) unreachable;
|
if (slice_rest.len != 10) unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "constant equal function pointers" {
|
test "constant equal function pointers" {
|
||||||
const alias = emptyFn;
|
const alias = emptyFn;
|
||||||
assert(comptime x: {break :x emptyFn == alias;});
|
assert(comptime x: {
|
||||||
|
break :x emptyFn == alias;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emptyFn() void {}
|
fn emptyFn() void {}
|
||||||
|
|
||||||
|
|
||||||
test "hex escape" {
|
test "hex escape" {
|
||||||
assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
|
assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
|
||||||
}
|
}
|
||||||
@ -219,7 +232,7 @@ test "string escapes" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "multiline string" {
|
test "multiline string" {
|
||||||
const s1 =
|
const s1 =
|
||||||
\\one
|
\\one
|
||||||
\\two)
|
\\two)
|
||||||
\\three
|
\\three
|
||||||
@ -229,7 +242,7 @@ test "multiline string" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "multiline C string" {
|
test "multiline C string" {
|
||||||
const s1 =
|
const s1 =
|
||||||
c\\one
|
c\\one
|
||||||
c\\two)
|
c\\two)
|
||||||
c\\three
|
c\\three
|
||||||
@ -238,18 +251,16 @@ test "multiline C string" {
|
|||||||
assert(cstr.cmp(s1, s2) == 0);
|
assert(cstr.cmp(s1, s2) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "type equality" {
|
test "type equality" {
|
||||||
assert(&const u8 != &u8);
|
assert(&const u8 != &u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const global_a: i32 = 1234;
|
const global_a: i32 = 1234;
|
||||||
const global_b: &const i32 = &global_a;
|
const global_b: &const i32 = &global_a;
|
||||||
const global_c: &const f32 = @ptrCast(&const f32, global_b);
|
const global_c: &const f32 = @ptrCast(&const f32, global_b);
|
||||||
test "compile time global reinterpret" {
|
test "compile time global reinterpret" {
|
||||||
const d = @ptrCast(&const i32, global_c);
|
const d = @ptrCast(&const i32, global_c);
|
||||||
assert(*d == 1234);
|
assert(d.* == 1234);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "explicit cast maybe pointers" {
|
test "explicit cast maybe pointers" {
|
||||||
@ -261,12 +272,11 @@ test "generic malloc free" {
|
|||||||
const a = memAlloc(u8, 10) catch unreachable;
|
const a = memAlloc(u8, 10) catch unreachable;
|
||||||
memFree(u8, a);
|
memFree(u8, a);
|
||||||
}
|
}
|
||||||
var some_mem : [100]u8 = undefined;
|
var some_mem: [100]u8 = undefined;
|
||||||
fn memAlloc(comptime T: type, n: usize) error![]T {
|
fn memAlloc(comptime T: type, n: usize) error![]T {
|
||||||
return @ptrCast(&T, &some_mem[0])[0..n];
|
return @ptrCast(&T, &some_mem[0])[0..n];
|
||||||
}
|
}
|
||||||
fn memFree(comptime T: type, memory: []T) void { }
|
fn memFree(comptime T: type, memory: []T) void {}
|
||||||
|
|
||||||
|
|
||||||
test "cast undefined" {
|
test "cast undefined" {
|
||||||
const array: [100]u8 = undefined;
|
const array: [100]u8 = undefined;
|
||||||
@ -275,32 +285,35 @@ test "cast undefined" {
|
|||||||
}
|
}
|
||||||
fn testCastUndefined(x: []const u8) void {}
|
fn testCastUndefined(x: []const u8) void {}
|
||||||
|
|
||||||
|
|
||||||
test "cast small unsigned to larger signed" {
|
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 { return x; }
|
fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
|
||||||
fn castSmallUnsignedToLargerSigned2(x: u16) i64 { return x; }
|
return 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 { return 1234; }
|
fn inner() i32 {
|
||||||
|
return 1234;
|
||||||
|
}
|
||||||
fn outer() i64 {
|
fn outer() i64 {
|
||||||
return inner();
|
return inner();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "pointer dereferencing" {
|
test "pointer dereferencing" {
|
||||||
var x = i32(3);
|
var x = i32(3);
|
||||||
const y = &x;
|
const y = &x;
|
||||||
|
|
||||||
*y += 1;
|
y.* += 1;
|
||||||
|
|
||||||
assert(x == 4);
|
assert(x == 4);
|
||||||
assert(*y == 4);
|
assert(y.* == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "call result of if else expression" {
|
test "call result of if else expression" {
|
||||||
@ -310,9 +323,12 @@ 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 { return "a"; }
|
fn fA() []const u8 {
|
||||||
fn fB() []const u8 { return "b"; }
|
return "a";
|
||||||
|
}
|
||||||
|
fn fB() []const u8 {
|
||||||
|
return "b";
|
||||||
|
}
|
||||||
|
|
||||||
test "const expression eval handling of variables" {
|
test "const expression eval handling of variables" {
|
||||||
var x = true;
|
var x = true;
|
||||||
@ -321,8 +337,6 @@ test "const expression eval handling of variables" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test "constant enum initialization with differing sizes" {
|
test "constant enum initialization with differing sizes" {
|
||||||
test3_1(test3_foo);
|
test3_1(test3_foo);
|
||||||
test3_2(test3_bar);
|
test3_2(test3_bar);
|
||||||
@ -336,10 +350,17 @@ const Test3Point = struct {
|
|||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
};
|
};
|
||||||
const test3_foo = Test3Foo { .Three = Test3Point {.x = 3, .y = 4}};
|
const test3_foo = Test3Foo {
|
||||||
const test3_bar = Test3Foo { .Two = 13};
|
.Three = Test3Point {
|
||||||
|
.x = 3,
|
||||||
|
.y = 4,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const test3_bar = Test3Foo {
|
||||||
|
.Two = 13,
|
||||||
|
};
|
||||||
fn test3_1(f: &const Test3Foo) void {
|
fn test3_1(f: &const Test3Foo) void {
|
||||||
switch (*f) {
|
switch (f.*) {
|
||||||
Test3Foo.Three => |pt| {
|
Test3Foo.Three => |pt| {
|
||||||
assert(pt.x == 3);
|
assert(pt.x == 3);
|
||||||
assert(pt.y == 4);
|
assert(pt.y == 4);
|
||||||
@ -348,7 +369,7 @@ fn test3_1(f: &const Test3Foo) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn test3_2(f: &const Test3Foo) void {
|
fn test3_2(f: &const Test3Foo) void {
|
||||||
switch (*f) {
|
switch (f.*) {
|
||||||
Test3Foo.Two => |x| {
|
Test3Foo.Two => |x| {
|
||||||
assert(x == 13);
|
assert(x == 13);
|
||||||
},
|
},
|
||||||
@ -356,23 +377,19 @@ fn test3_2(f: &const Test3Foo) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "character literals" {
|
test "character literals" {
|
||||||
assert('\'' == single_quote);
|
assert('\'' == single_quote);
|
||||||
}
|
}
|
||||||
const single_quote = '\'';
|
const single_quote = '\'';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test "take address of parameter" {
|
test "take address of parameter" {
|
||||||
testTakeAddressOfParameter(12.34);
|
testTakeAddressOfParameter(12.34);
|
||||||
}
|
}
|
||||||
fn testTakeAddressOfParameter(f: f32) void {
|
fn testTakeAddressOfParameter(f: f32) void {
|
||||||
const f_ptr = &f;
|
const f_ptr = &f;
|
||||||
assert(*f_ptr == 12.34);
|
assert(f_ptr.* == 12.34);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "pointer comparison" {
|
test "pointer comparison" {
|
||||||
const a = ([]const u8)("a");
|
const a = ([]const u8)("a");
|
||||||
const b = &a;
|
const b = &a;
|
||||||
@ -382,23 +399,30 @@ fn ptrEql(a: &const []const u8, b: &const []const u8) bool {
|
|||||||
return a == b;
|
return a == b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "C string concatenation" {
|
test "C string concatenation" {
|
||||||
const a = c"OK" ++ c" IT " ++ c"WORKED";
|
const a = c"OK" ++ c" IT " ++ c"WORKED";
|
||||||
const b = c"OK IT WORKED";
|
const b = c"OK IT WORKED";
|
||||||
|
|
||||||
const len = cstr.len(b);
|
const len = cstr.len(b);
|
||||||
const len_with_null = len + 1;
|
const len_with_null = len + 1;
|
||||||
{var i: u32 = 0; while (i < len_with_null) : (i += 1) {
|
{
|
||||||
assert(a[i] == b[i]);
|
var i: u32 = 0;
|
||||||
}}
|
while (i < len_with_null) : (i += 1) {
|
||||||
|
assert(a[i] == b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
assert(a[len] == 0);
|
assert(a[len] == 0);
|
||||||
assert(b[len] == 0);
|
assert(b[len] == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "cast slice to u8 slice" {
|
test "cast slice to u8 slice" {
|
||||||
assert(@sizeOf(i32) == 4);
|
assert(@sizeOf(i32) == 4);
|
||||||
var big_thing_array = []i32{1, 2, 3, 4};
|
var big_thing_array = []i32 {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
};
|
||||||
const big_thing_slice: []i32 = big_thing_array[0..];
|
const big_thing_slice: []i32 = big_thing_array[0..];
|
||||||
const bytes = ([]u8)(big_thing_slice);
|
const bytes = ([]u8)(big_thing_slice);
|
||||||
assert(bytes.len == 4 * 4);
|
assert(bytes.len == 4 * 4);
|
||||||
@ -421,25 +445,22 @@ test "pointer to void return type" {
|
|||||||
}
|
}
|
||||||
fn testPointerToVoidReturnType() error!void {
|
fn testPointerToVoidReturnType() error!void {
|
||||||
const a = testPointerToVoidReturnType2();
|
const a = testPointerToVoidReturnType2();
|
||||||
return *a;
|
return a.*;
|
||||||
}
|
}
|
||||||
const test_pointer_to_void_return_type_x = void{};
|
const test_pointer_to_void_return_type_x = void{};
|
||||||
fn testPointerToVoidReturnType2() &const void {
|
fn testPointerToVoidReturnType2() &const void {
|
||||||
return &test_pointer_to_void_return_type_x;
|
return &test_pointer_to_void_return_type_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "non const ptr to aliased type" {
|
test "non const ptr to aliased type" {
|
||||||
const int = i32;
|
const int = i32;
|
||||||
assert(?&int == ?&i32);
|
assert(?&int == ?&i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test "array 2D const double ptr" {
|
test "array 2D const double ptr" {
|
||||||
const rect_2d_vertexes = [][1]f32 {
|
const rect_2d_vertexes = [][1]f32 {
|
||||||
[]f32{1.0},
|
[]f32 {1.0},
|
||||||
[]f32{2.0},
|
[]f32 {2.0},
|
||||||
};
|
};
|
||||||
testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
|
testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
|
||||||
}
|
}
|
||||||
@ -450,10 +471,21 @@ fn testArray2DConstDoublePtr(ptr: &const f32) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Tid = builtin.TypeId;
|
const Tid = builtin.TypeId;
|
||||||
const AStruct = struct { x: i32, };
|
const AStruct = struct {
|
||||||
const AnEnum = enum { One, Two, };
|
x: i32,
|
||||||
const AUnionEnum = union(enum) { One: i32, Two: void, };
|
};
|
||||||
const AUnion = union { One: void, Two: void };
|
const AnEnum = enum {
|
||||||
|
One,
|
||||||
|
Two,
|
||||||
|
};
|
||||||
|
const AUnionEnum = union(enum) {
|
||||||
|
One: i32,
|
||||||
|
Two: void,
|
||||||
|
};
|
||||||
|
const AUnion = union {
|
||||||
|
One: void,
|
||||||
|
Two: void,
|
||||||
|
};
|
||||||
|
|
||||||
test "@typeId" {
|
test "@typeId" {
|
||||||
comptime {
|
comptime {
|
||||||
@ -481,9 +513,11 @@ test "@typeId" {
|
|||||||
assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
|
assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
|
||||||
assert(@typeId(AUnionEnum) == Tid.Union);
|
assert(@typeId(AUnionEnum) == Tid.Union);
|
||||||
assert(@typeId(AUnion) == Tid.Union);
|
assert(@typeId(AUnion) == Tid.Union);
|
||||||
assert(@typeId(fn()void) == Tid.Fn);
|
assert(@typeId(fn() void) == Tid.Fn);
|
||||||
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
|
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
|
||||||
assert(@typeId(@typeOf(x: {break :x 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
|
||||||
@ -499,8 +533,7 @@ test "@canImplicitCast" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "@typeName" {
|
test "@typeName" {
|
||||||
const Struct = struct {
|
const Struct = struct {};
|
||||||
};
|
|
||||||
const Union = union {
|
const Union = union {
|
||||||
unused: u8,
|
unused: u8,
|
||||||
};
|
};
|
||||||
@ -525,14 +558,19 @@ fn TypeFromFn(comptime T: type) type {
|
|||||||
test "volatile load and store" {
|
test "volatile load and store" {
|
||||||
var number: i32 = 1234;
|
var number: i32 = 1234;
|
||||||
const ptr = (&volatile i32)(&number);
|
const ptr = (&volatile i32)(&number);
|
||||||
*ptr += 1;
|
ptr.* += 1;
|
||||||
assert(*ptr == 1235);
|
assert(ptr.* == 1235);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "slice string literal has type []const u8" {
|
test "slice string literal has type []const u8" {
|
||||||
comptime {
|
comptime {
|
||||||
assert(@typeOf("aoeu"[0..]) == []const u8);
|
assert(@typeOf("aoeu"[0..]) == []const u8);
|
||||||
const array = []i32{1, 2, 3, 4};
|
const array = []i32 {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
};
|
||||||
assert(@typeOf(array[0..]) == []const i32);
|
assert(@typeOf(array[0..]) == []const i32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -544,12 +582,15 @@ const GDTEntry = struct {
|
|||||||
field: i32,
|
field: i32,
|
||||||
};
|
};
|
||||||
var gdt = []GDTEntry {
|
var gdt = []GDTEntry {
|
||||||
GDTEntry {.field = 1},
|
GDTEntry {
|
||||||
GDTEntry {.field = 2},
|
.field = 1,
|
||||||
|
},
|
||||||
|
GDTEntry {
|
||||||
|
.field = 2,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
var global_ptr = &gdt[0];
|
var global_ptr = &gdt[0];
|
||||||
|
|
||||||
|
|
||||||
// can't really run this test but we can make sure it has no compile error
|
// can't really run this test but we can make sure it has no compile error
|
||||||
// and generates code
|
// and generates code
|
||||||
const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000];
|
const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000];
|
||||||
@ -584,7 +625,7 @@ test "comptime if inside runtime while which unconditionally breaks" {
|
|||||||
}
|
}
|
||||||
fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
|
fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
|
||||||
while (cond) {
|
while (cond) {
|
||||||
if (false) { }
|
if (false) {}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -607,7 +648,9 @@ fn testStructInFn() void {
|
|||||||
kind: BlockKind,
|
kind: BlockKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
var block = Block { .kind = 1234 };
|
var block = Block {
|
||||||
|
.kind = 1234,
|
||||||
|
};
|
||||||
|
|
||||||
block.kind += 1;
|
block.kind += 1;
|
||||||
|
|
||||||
@ -617,7 +660,9 @@ fn testStructInFn() void {
|
|||||||
fn fnThatClosesOverLocalConst() type {
|
fn fnThatClosesOverLocalConst() type {
|
||||||
const c = 1;
|
const c = 1;
|
||||||
return struct {
|
return struct {
|
||||||
fn g() i32 { return c; }
|
fn g() i32 {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,22 +680,29 @@ fn thisIsAColdFn() void {
|
|||||||
@setCold(true);
|
@setCold(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PackedStruct = packed struct {
|
||||||
const PackedStruct = packed struct { a: u8, b: u8, };
|
a: u8,
|
||||||
const PackedUnion = packed union { a: u8, b: u32, };
|
b: u8,
|
||||||
const PackedEnum = packed enum { A, B, };
|
};
|
||||||
|
const PackedUnion = packed union {
|
||||||
|
a: u8,
|
||||||
|
b: u32,
|
||||||
|
};
|
||||||
|
const PackedEnum = packed enum {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
};
|
||||||
|
|
||||||
test "packed struct, enum, union parameters in extern function" {
|
test "packed struct, enum, union parameters in extern function" {
|
||||||
testPackedStuff(
|
testPackedStuff(PackedStruct {
|
||||||
PackedStruct{.a = 1, .b = 2},
|
.a = 1,
|
||||||
PackedUnion{.a = 1},
|
.b = 2,
|
||||||
PackedEnum.A,
|
}, PackedUnion {
|
||||||
);
|
.a = 1,
|
||||||
}
|
}, PackedEnum.A);
|
||||||
|
|
||||||
export fn testPackedStuff(a: &const PackedStruct, b: &const PackedUnion, c: PackedEnum) void {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export fn testPackedStuff(a: &const PackedStruct, b: &const PackedUnion, c: PackedEnum) void {}
|
||||||
|
|
||||||
test "slicing zero length array" {
|
test "slicing zero length array" {
|
||||||
const s1 = ""[0..];
|
const s1 = ""[0..];
|
||||||
@ -661,7 +713,6 @@ test "slicing zero length array" {
|
|||||||
assert(mem.eql(u32, s2, []u32{}));
|
assert(mem.eql(u32, s2, []u32{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const addr1 = @ptrCast(&const u8, emptyFn);
|
const addr1 = @ptrCast(&const u8, emptyFn);
|
||||||
test "comptime cast fn to ptr" {
|
test "comptime cast fn to ptr" {
|
||||||
const addr2 = @ptrCast(&const u8, emptyFn);
|
const addr2 = @ptrCast(&const u8, emptyFn);
|
||||||
|
@ -8,7 +8,7 @@ test "namespace depends on compile var" {
|
|||||||
assert(!some_namespace.a_bool);
|
assert(!some_namespace.a_bool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const some_namespace = switch(builtin.os) {
|
const some_namespace = switch (builtin.os) {
|
||||||
builtin.Os.linux => @import("a.zig"),
|
builtin.Os.linux => @import("a.zig"),
|
||||||
else => @import("b.zig"),
|
else => @import("b.zig"),
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const assert = @import("std").debug.assert;
|
const assert = @import("std").debug.assert;
|
||||||
|
|
||||||
test "nullable type" {
|
test "nullable type" {
|
||||||
const x : ?bool = true;
|
const x: ?bool = true;
|
||||||
|
|
||||||
if (x) |y| {
|
if (x) |y| {
|
||||||
if (y) {
|
if (y) {
|
||||||
@ -13,13 +13,13 @@ test "nullable type" {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
const next_x : ?i32 = null;
|
const next_x: ?i32 = null;
|
||||||
|
|
||||||
const z = next_x ?? 1234;
|
const z = next_x ?? 1234;
|
||||||
|
|
||||||
assert(z == 1234);
|
assert(z == 1234);
|
||||||
|
|
||||||
const final_x : ?i32 = 13;
|
const final_x: ?i32 = 13;
|
||||||
|
|
||||||
const num = final_x ?? unreachable;
|
const num = final_x ?? unreachable;
|
||||||
|
|
||||||
@ -30,19 +30,17 @@ test "test maybe object and get a pointer to the inner value" {
|
|||||||
var maybe_bool: ?bool = true;
|
var maybe_bool: ?bool = true;
|
||||||
|
|
||||||
if (maybe_bool) |*b| {
|
if (maybe_bool) |*b| {
|
||||||
*b = false;
|
b.* = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(??maybe_bool == false);
|
assert(??maybe_bool == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "rhs maybe unwrap return" {
|
test "rhs maybe unwrap return" {
|
||||||
const x: ?bool = true;
|
const x: ?bool = true;
|
||||||
const y = x ?? return;
|
const y = x ?? return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "maybe return" {
|
test "maybe return" {
|
||||||
maybeReturnImpl();
|
maybeReturnImpl();
|
||||||
comptime maybeReturnImpl();
|
comptime maybeReturnImpl();
|
||||||
@ -50,8 +48,7 @@ test "maybe return" {
|
|||||||
|
|
||||||
fn maybeReturnImpl() void {
|
fn maybeReturnImpl() void {
|
||||||
assert(??foo(1235));
|
assert(??foo(1235));
|
||||||
if (foo(null) != null)
|
if (foo(null) != null) unreachable;
|
||||||
unreachable;
|
|
||||||
assert(!??foo(1234));
|
assert(!??foo(1234));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,12 +57,16 @@ fn foo(x: ?i32) ?bool {
|
|||||||
return value > 1234;
|
return value > 1234;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "if var maybe pointer" {
|
test "if var maybe pointer" {
|
||||||
assert(shouldBeAPlus1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15);
|
assert(shouldBeAPlus1(Particle {
|
||||||
|
.a = 14,
|
||||||
|
.b = 1,
|
||||||
|
.c = 1,
|
||||||
|
.d = 1,
|
||||||
|
}) == 15);
|
||||||
}
|
}
|
||||||
fn shouldBeAPlus1(p: &const Particle) u64 {
|
fn shouldBeAPlus1(p: &const Particle) u64 {
|
||||||
var maybe_particle: ?Particle = *p;
|
var maybe_particle: ?Particle = p.*;
|
||||||
if (maybe_particle) |*particle| {
|
if (maybe_particle) |*particle| {
|
||||||
particle.a += 1;
|
particle.a += 1;
|
||||||
}
|
}
|
||||||
@ -81,7 +82,6 @@ const Particle = struct {
|
|||||||
d: u64,
|
d: u64,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
test "null literal outside function" {
|
test "null literal outside function" {
|
||||||
const is_null = here_is_a_null_literal.context == null;
|
const is_null = here_is_a_null_literal.context == null;
|
||||||
assert(is_null);
|
assert(is_null);
|
||||||
@ -96,7 +96,6 @@ const here_is_a_null_literal = SillyStruct {
|
|||||||
.context = null,
|
.context = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
test "test null runtime" {
|
test "test null runtime" {
|
||||||
testTestNullRuntime(null);
|
testTestNullRuntime(null);
|
||||||
}
|
}
|
||||||
@ -123,8 +122,6 @@ fn bar(x: ?void) ?void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const StructWithNullable = struct {
|
const StructWithNullable = struct {
|
||||||
field: ?i32,
|
field: ?i32,
|
||||||
};
|
};
|
||||||
|
@ -23,7 +23,7 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void {
|
|||||||
if (c) {
|
if (c) {
|
||||||
const output_path = b;
|
const output_path = b;
|
||||||
|
|
||||||
if (c2) { }
|
if (c2) {}
|
||||||
|
|
||||||
a(output_path);
|
a(output_path);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ test "reflection: function return type, var args, and param types" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dummy(a: bool, b: i32, c: f32) i32 { return 1234; }
|
fn dummy(a: bool, b: i32, c: f32) i32 {
|
||||||
|
return 1234;
|
||||||
|
}
|
||||||
fn dummy_varargs(args: ...) void {}
|
fn dummy_varargs(args: ...) void {}
|
||||||
|
|
||||||
test "reflection: struct member types and names" {
|
test "reflection: struct member types and names" {
|
||||||
@ -54,7 +56,6 @@ test "reflection: enum member types and names" {
|
|||||||
assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
|
assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
|
||||||
assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
|
assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "reflection: @field" {
|
test "reflection: @field" {
|
||||||
|
@ -18,7 +18,11 @@ test "slice child property" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "runtime safety lets us slice from len..len" {
|
test "runtime safety lets us slice from len..len" {
|
||||||
var an_array = []u8{1, 2, 3};
|
var an_array = []u8 {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
};
|
||||||
assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
|
assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +31,7 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "implicitly cast array of size 0 to slice" {
|
test "implicitly cast array of size 0 to slice" {
|
||||||
var msg = []u8 {};
|
var msg = []u8{};
|
||||||
assertLenIsZero(msg);
|
assertLenIsZero(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,9 +2,11 @@ const assert = @import("std").debug.assert;
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
const StructWithNoFields = struct {
|
const StructWithNoFields = struct {
|
||||||
fn add(a: i32, b: i32) i32 { return a + b; }
|
fn add(a: i32, b: i32) i32 {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const empty_global_instance = StructWithNoFields {};
|
const empty_global_instance = StructWithNoFields{};
|
||||||
|
|
||||||
test "call struct static method" {
|
test "call struct static method" {
|
||||||
const result = StructWithNoFields.add(3, 4);
|
const result = StructWithNoFields.add(3, 4);
|
||||||
@ -34,12 +36,11 @@ test "void struct fields" {
|
|||||||
assert(@sizeOf(VoidStructFieldsFoo) == 4);
|
assert(@sizeOf(VoidStructFieldsFoo) == 4);
|
||||||
}
|
}
|
||||||
const VoidStructFieldsFoo = struct {
|
const VoidStructFieldsFoo = struct {
|
||||||
a : void,
|
a: void,
|
||||||
b : i32,
|
b: i32,
|
||||||
c : void,
|
c: void,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
test "structs" {
|
test "structs" {
|
||||||
var foo: StructFoo = undefined;
|
var foo: StructFoo = undefined;
|
||||||
@memset(@ptrCast(&u8, &foo), 0, @sizeOf(StructFoo));
|
@memset(@ptrCast(&u8, &foo), 0, @sizeOf(StructFoo));
|
||||||
@ -50,9 +51,9 @@ test "structs" {
|
|||||||
assert(foo.c == 100);
|
assert(foo.c == 100);
|
||||||
}
|
}
|
||||||
const StructFoo = struct {
|
const StructFoo = struct {
|
||||||
a : i32,
|
a: i32,
|
||||||
b : bool,
|
b: bool,
|
||||||
c : f32,
|
c: f32,
|
||||||
};
|
};
|
||||||
fn testFoo(foo: &const StructFoo) void {
|
fn testFoo(foo: &const StructFoo) void {
|
||||||
assert(foo.b);
|
assert(foo.b);
|
||||||
@ -61,7 +62,6 @@ fn testMutation(foo: &StructFoo) void {
|
|||||||
foo.c = 100;
|
foo.c = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Node = struct {
|
const Node = struct {
|
||||||
val: Val,
|
val: Val,
|
||||||
next: &Node,
|
next: &Node,
|
||||||
@ -72,10 +72,10 @@ const Val = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test "struct point to self" {
|
test "struct point to self" {
|
||||||
var root : Node = undefined;
|
var root: Node = undefined;
|
||||||
root.val.x = 1;
|
root.val.x = 1;
|
||||||
|
|
||||||
var node : Node = undefined;
|
var node: Node = undefined;
|
||||||
node.next = &root;
|
node.next = &root;
|
||||||
node.val.x = 2;
|
node.val.x = 2;
|
||||||
|
|
||||||
@ -85,8 +85,8 @@ test "struct point to self" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "struct byval assign" {
|
test "struct byval assign" {
|
||||||
var foo1 : StructFoo = undefined;
|
var foo1: StructFoo = undefined;
|
||||||
var foo2 : StructFoo = undefined;
|
var foo2: StructFoo = undefined;
|
||||||
|
|
||||||
foo1.a = 1234;
|
foo1.a = 1234;
|
||||||
foo2.a = 0;
|
foo2.a = 0;
|
||||||
@ -96,46 +96,57 @@ test "struct byval assign" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn structInitializer() void {
|
fn structInitializer() void {
|
||||||
const val = Val { .x = 42 };
|
const val = Val {
|
||||||
|
.x = 42,
|
||||||
|
};
|
||||||
assert(val.x == 42);
|
assert(val.x == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "fn call of struct field" {
|
test "fn call of struct field" {
|
||||||
assert(callStructField(Foo {.ptr = aFunc,}) == 13);
|
assert(callStructField(Foo {
|
||||||
|
.ptr = aFunc,
|
||||||
|
}) == 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Foo = struct {
|
const Foo = struct {
|
||||||
ptr: fn() i32,
|
ptr: fn() i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn aFunc() i32 { return 13; }
|
fn aFunc() i32 {
|
||||||
|
return 13;
|
||||||
|
}
|
||||||
|
|
||||||
fn callStructField(foo: &const Foo) i32 {
|
fn callStructField(foo: &const Foo) i32 {
|
||||||
return foo.ptr();
|
return foo.ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "store member function in variable" {
|
test "store member function in variable" {
|
||||||
const instance = MemberFnTestFoo { .x = 1234, };
|
const instance = MemberFnTestFoo {
|
||||||
|
.x = 1234,
|
||||||
|
};
|
||||||
const memberFn = MemberFnTestFoo.member;
|
const memberFn = MemberFnTestFoo.member;
|
||||||
const result = memberFn(instance);
|
const result = memberFn(instance);
|
||||||
assert(result == 1234);
|
assert(result == 1234);
|
||||||
}
|
}
|
||||||
const MemberFnTestFoo = struct {
|
const MemberFnTestFoo = struct {
|
||||||
x: i32,
|
x: i32,
|
||||||
fn member(foo: &const MemberFnTestFoo) i32 { return foo.x; }
|
fn member(foo: &const MemberFnTestFoo) i32 {
|
||||||
|
return foo.x;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
test "call member function directly" {
|
test "call member function directly" {
|
||||||
const instance = MemberFnTestFoo { .x = 1234, };
|
const instance = MemberFnTestFoo {
|
||||||
|
.x = 1234,
|
||||||
|
};
|
||||||
const result = MemberFnTestFoo.member(instance);
|
const result = MemberFnTestFoo.member(instance);
|
||||||
assert(result == 1234);
|
assert(result == 1234);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "member functions" {
|
test "member functions" {
|
||||||
const r = MemberFnRand {.seed = 1234};
|
const r = MemberFnRand {
|
||||||
|
.seed = 1234,
|
||||||
|
};
|
||||||
assert(r.getSeed() == 1234);
|
assert(r.getSeed() == 1234);
|
||||||
}
|
}
|
||||||
const MemberFnRand = struct {
|
const MemberFnRand = struct {
|
||||||
@ -170,17 +181,16 @@ const EmptyStruct = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
test "return empty struct from fn" {
|
test "return empty struct from fn" {
|
||||||
_ = testReturnEmptyStructFromFn();
|
_ = testReturnEmptyStructFromFn();
|
||||||
}
|
}
|
||||||
const EmptyStruct2 = struct {};
|
const EmptyStruct2 = struct {};
|
||||||
fn testReturnEmptyStructFromFn() EmptyStruct2 {
|
fn testReturnEmptyStructFromFn() EmptyStruct2 {
|
||||||
return EmptyStruct2 {};
|
return EmptyStruct2{};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "pass slice of empty struct to fn" {
|
test "pass slice of empty struct to fn" {
|
||||||
assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1);
|
assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2 {EmptyStruct2{}}) == 1);
|
||||||
}
|
}
|
||||||
fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
|
fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
|
||||||
return slice.len;
|
return slice.len;
|
||||||
@ -201,7 +211,6 @@ test "packed struct" {
|
|||||||
assert(four == 4);
|
assert(four == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const BitField1 = packed struct {
|
const BitField1 = packed struct {
|
||||||
a: u3,
|
a: u3,
|
||||||
b: u3,
|
b: u3,
|
||||||
@ -301,7 +310,7 @@ test "packed array 24bits" {
|
|||||||
assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
|
assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
|
var bytes = []u8 {0} ** (@sizeOf(FooArray24Bits) + 1);
|
||||||
bytes[bytes.len - 1] = 0xaa;
|
bytes[bytes.len - 1] = 0xaa;
|
||||||
const ptr = &([]FooArray24Bits)(bytes[0..bytes.len - 1])[0];
|
const ptr = &([]FooArray24Bits)(bytes[0..bytes.len - 1])[0];
|
||||||
assert(ptr.a == 0);
|
assert(ptr.a == 0);
|
||||||
@ -351,7 +360,7 @@ test "aligned array of packed struct" {
|
|||||||
assert(@sizeOf(FooArrayOfAligned) == 2 * 2);
|
assert(@sizeOf(FooArrayOfAligned) == 2 * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);
|
var bytes = []u8 {0xbb} ** @sizeOf(FooArrayOfAligned);
|
||||||
const ptr = &([]FooArrayOfAligned)(bytes[0..bytes.len])[0];
|
const ptr = &([]FooArrayOfAligned)(bytes[0..bytes.len])[0];
|
||||||
|
|
||||||
assert(ptr.a[0].a == 0xbb);
|
assert(ptr.a[0].a == 0xbb);
|
||||||
@ -360,11 +369,15 @@ test "aligned array of packed struct" {
|
|||||||
assert(ptr.a[1].b == 0xbb);
|
assert(ptr.a[1].b == 0xbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test "runtime struct initialization of bitfield" {
|
test "runtime struct initialization of bitfield" {
|
||||||
const s1 = Nibbles { .x = x1, .y = x1 };
|
const s1 = Nibbles {
|
||||||
const s2 = Nibbles { .x = u4(x2), .y = u4(x2) };
|
.x = x1,
|
||||||
|
.y = x1,
|
||||||
|
};
|
||||||
|
const s2 = Nibbles {
|
||||||
|
.x = u4(x2),
|
||||||
|
.y = u4(x2),
|
||||||
|
};
|
||||||
|
|
||||||
assert(s1.x == x1);
|
assert(s1.x == x1);
|
||||||
assert(s1.y == x1);
|
assert(s1.y == x1);
|
||||||
@ -394,7 +407,7 @@ test "native bit field understands endianness" {
|
|||||||
var all: u64 = 0x7765443322221111;
|
var all: u64 = 0x7765443322221111;
|
||||||
var bytes: [8]u8 = undefined;
|
var bytes: [8]u8 = undefined;
|
||||||
@memcpy(&bytes[0], @ptrCast(&u8, &all), 8);
|
@memcpy(&bytes[0], @ptrCast(&u8, &all), 8);
|
||||||
var bitfields = *@ptrCast(&Bitfields, &bytes[0]);
|
var bitfields = @ptrCast(&Bitfields, &bytes[0]).*;
|
||||||
|
|
||||||
assert(bitfields.f1 == 0x1111);
|
assert(bitfields.f1 == 0x1111);
|
||||||
assert(bitfields.f2 == 0x2222);
|
assert(bitfields.f2 == 0x2222);
|
||||||
|
@ -19,4 +19,3 @@ pub const Node = struct {
|
|||||||
pub const NodeLineComment = struct {
|
pub const NodeLineComment = struct {
|
||||||
base: Node,
|
base: Node,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ const Node = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test "struct contains slice of itself" {
|
test "struct contains slice of itself" {
|
||||||
var other_nodes = []Node{
|
var other_nodes = []Node {
|
||||||
Node {
|
Node {
|
||||||
.payload = 31,
|
.payload = 31,
|
||||||
.children = []Node{},
|
.children = []Node{},
|
||||||
|
@ -6,7 +6,10 @@ test "switch with numbers" {
|
|||||||
|
|
||||||
fn testSwitchWithNumbers(x: u32) void {
|
fn testSwitchWithNumbers(x: u32) void {
|
||||||
const result = switch (x) {
|
const result = switch (x) {
|
||||||
1, 2, 3, 4 ... 8 => false,
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4 ... 8 => false,
|
||||||
13 => true,
|
13 => true,
|
||||||
else => false,
|
else => false,
|
||||||
};
|
};
|
||||||
@ -34,8 +37,10 @@ test "implicit comptime switch" {
|
|||||||
const result = switch (x) {
|
const result = switch (x) {
|
||||||
3 => 10,
|
3 => 10,
|
||||||
4 => 11,
|
4 => 11,
|
||||||
5, 6 => 12,
|
5,
|
||||||
7, 8 => 13,
|
6 => 12,
|
||||||
|
7,
|
||||||
|
8 => 13,
|
||||||
else => 14,
|
else => 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,7 +66,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "switch statement" {
|
test "switch statement" {
|
||||||
nonConstSwitch(SwitchStatmentFoo.C);
|
nonConstSwitch(SwitchStatmentFoo.C);
|
||||||
}
|
}
|
||||||
@ -81,11 +85,16 @@ const SwitchStatmentFoo = enum {
|
|||||||
D,
|
D,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
test "switch prong with variable" {
|
test "switch prong with variable" {
|
||||||
switchProngWithVarFn(SwitchProngWithVarEnum { .One = 13});
|
switchProngWithVarFn(SwitchProngWithVarEnum {
|
||||||
switchProngWithVarFn(SwitchProngWithVarEnum { .Two = 13.0});
|
.One = 13,
|
||||||
switchProngWithVarFn(SwitchProngWithVarEnum { .Meh = {}});
|
});
|
||||||
|
switchProngWithVarFn(SwitchProngWithVarEnum {
|
||||||
|
.Two = 13.0,
|
||||||
|
});
|
||||||
|
switchProngWithVarFn(SwitchProngWithVarEnum {
|
||||||
|
.Meh = {},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const SwitchProngWithVarEnum = union(enum) {
|
const SwitchProngWithVarEnum = union(enum) {
|
||||||
One: i32,
|
One: i32,
|
||||||
@ -93,7 +102,7 @@ const SwitchProngWithVarEnum = union(enum) {
|
|||||||
Meh: void,
|
Meh: void,
|
||||||
};
|
};
|
||||||
fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) void {
|
fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) void {
|
||||||
switch(*a) {
|
switch (a.*) {
|
||||||
SwitchProngWithVarEnum.One => |x| {
|
SwitchProngWithVarEnum.One => |x| {
|
||||||
assert(x == 13);
|
assert(x == 13);
|
||||||
},
|
},
|
||||||
@ -112,9 +121,11 @@ test "switch on enum using pointer capture" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn testSwitchEnumPtrCapture() void {
|
fn testSwitchEnumPtrCapture() void {
|
||||||
var value = SwitchProngWithVarEnum { .One = 1234 };
|
var value = SwitchProngWithVarEnum {
|
||||||
|
.One = 1234,
|
||||||
|
};
|
||||||
switch (value) {
|
switch (value) {
|
||||||
SwitchProngWithVarEnum.One => |*x| *x += 1,
|
SwitchProngWithVarEnum.One => |*x| x.* += 1,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
switch (value) {
|
switch (value) {
|
||||||
@ -125,8 +136,12 @@ fn testSwitchEnumPtrCapture() void {
|
|||||||
|
|
||||||
test "switch with multiple expressions" {
|
test "switch with multiple expressions" {
|
||||||
const x = switch (returnsFive()) {
|
const x = switch (returnsFive()) {
|
||||||
1, 2, 3 => 1,
|
1,
|
||||||
4, 5, 6 => 2,
|
2,
|
||||||
|
3 => 1,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6 => 2,
|
||||||
else => i32(3),
|
else => i32(3),
|
||||||
};
|
};
|
||||||
assert(x == 2);
|
assert(x == 2);
|
||||||
@ -135,14 +150,15 @@ fn returnsFive() i32 {
|
|||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Number = union(enum) {
|
const Number = union(enum) {
|
||||||
One: u64,
|
One: u64,
|
||||||
Two: u8,
|
Two: u8,
|
||||||
Three: f32,
|
Three: f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
const number = Number { .Three = 1.23 };
|
const number = Number {
|
||||||
|
.Three = 1.23,
|
||||||
|
};
|
||||||
|
|
||||||
fn returnsFalse() bool {
|
fn returnsFalse() bool {
|
||||||
switch (number) {
|
switch (number) {
|
||||||
@ -198,7 +214,8 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {
|
|||||||
return switch (x) {
|
return switch (x) {
|
||||||
0 ... 100 => u8(0),
|
0 ... 100 => u8(0),
|
||||||
101 ... 200 => 1,
|
101 ... 200 => 1,
|
||||||
201, 203 => 2,
|
201,
|
||||||
|
203 => 2,
|
||||||
202 => 4,
|
202 => 4,
|
||||||
204 ... 255 => 3,
|
204 ... 255 => 3,
|
||||||
};
|
};
|
||||||
|
@ -14,14 +14,18 @@ const FormValue = union(enum) {
|
|||||||
|
|
||||||
fn doThing(form_id: u64) error!FormValue {
|
fn doThing(form_id: u64) error!FormValue {
|
||||||
return switch (form_id) {
|
return switch (form_id) {
|
||||||
17 => FormValue { .Address = try readOnce() },
|
17 => FormValue {
|
||||||
|
.Address = try readOnce(),
|
||||||
|
},
|
||||||
else => error.InvalidDebugInfo,
|
else => error.InvalidDebugInfo,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "switch prong returns error enum" {
|
test "switch prong returns error enum" {
|
||||||
switch (doThing(17) catch unreachable) {
|
switch (doThing(17) catch unreachable) {
|
||||||
FormValue.Address => |payload| { assert(payload == 1); },
|
FormValue.Address => |payload| {
|
||||||
|
assert(payload == 1);
|
||||||
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
assert(read_count == 1);
|
assert(read_count == 1);
|
||||||
|
@ -7,8 +7,12 @@ const FormValue = union(enum) {
|
|||||||
|
|
||||||
fn foo(id: u64) !FormValue {
|
fn foo(id: u64) !FormValue {
|
||||||
return switch (id) {
|
return switch (id) {
|
||||||
2 => FormValue { .Two = true },
|
2 => FormValue {
|
||||||
1 => FormValue { .One = {} },
|
.Two = true,
|
||||||
|
},
|
||||||
|
1 => FormValue {
|
||||||
|
.One = {},
|
||||||
|
},
|
||||||
else => return error.Whatever,
|
else => return error.Whatever,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,12 @@ const assert = @import("std").debug.assert;
|
|||||||
test "try on error union" {
|
test "try on error union" {
|
||||||
tryOnErrorUnionImpl();
|
tryOnErrorUnionImpl();
|
||||||
comptime tryOnErrorUnionImpl();
|
comptime tryOnErrorUnionImpl();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tryOnErrorUnionImpl() void {
|
fn tryOnErrorUnionImpl() void {
|
||||||
const x = if (returnsTen()) |val|
|
const x = if (returnsTen()) |val| val + 1 else |err| switch (err) {
|
||||||
val + 1
|
error.ItBroke,
|
||||||
else |err| switch (err) {
|
error.NoMem => 1,
|
||||||
error.ItBroke, error.NoMem => 1,
|
|
||||||
error.CrappedOut => i32(2),
|
error.CrappedOut => i32(2),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
|
@ -63,6 +63,6 @@ test "assign undefined to struct with method" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "type name of undefined" {
|
test "type name of undefined" {
|
||||||
const x = undefined;
|
const x = undefined;
|
||||||
assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
|
assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
|
||||||
}
|
}
|
||||||
|
@ -10,38 +10,41 @@ const Agg = struct {
|
|||||||
val2: Value,
|
val2: Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
const v1 = Value { .Int = 1234 };
|
const v1 = Value{ .Int = 1234 };
|
||||||
const v2 = Value { .Array = []u8{3} ** 9 };
|
const v2 = Value{ .Array = []u8{3} ** 9 };
|
||||||
|
|
||||||
const err = (error!Agg)(Agg {
|
const err = (error!Agg)(Agg{
|
||||||
.val1 = v1,
|
.val1 = v1,
|
||||||
.val2 = v2,
|
.val2 = v2,
|
||||||
});
|
});
|
||||||
|
|
||||||
const array = []Value { v1, v2, v1, v2};
|
const array = []Value{
|
||||||
|
v1,
|
||||||
|
v2,
|
||||||
|
v1,
|
||||||
|
v2,
|
||||||
|
};
|
||||||
|
|
||||||
test "unions embedded in aggregate types" {
|
test "unions embedded in aggregate types" {
|
||||||
switch (array[1]) {
|
switch (array[1]) {
|
||||||
Value.Array => |arr| assert(arr[4] == 3),
|
Value.Array => |arr| assert(arr[4] == 3),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
switch((err catch unreachable).val1) {
|
switch ((err catch unreachable).val1) {
|
||||||
Value.Int => |x| assert(x == 1234),
|
Value.Int => |x| assert(x == 1234),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Foo = union {
|
const Foo = union {
|
||||||
float: f64,
|
float: f64,
|
||||||
int: i32,
|
int: i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
test "basic unions" {
|
test "basic unions" {
|
||||||
var foo = Foo { .int = 1 };
|
var foo = Foo{ .int = 1 };
|
||||||
assert(foo.int == 1);
|
assert(foo.int == 1);
|
||||||
foo = Foo {.float = 12.34};
|
foo = Foo{ .float = 12.34 };
|
||||||
assert(foo.float == 12.34);
|
assert(foo.float == 12.34);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,11 +59,11 @@ test "init union with runtime value" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setFloat(foo: &Foo, x: f64) void {
|
fn setFloat(foo: &Foo, x: f64) void {
|
||||||
*foo = Foo { .float = x };
|
foo.* = Foo{ .float = x };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setInt(foo: &Foo, x: i32) void {
|
fn setInt(foo: &Foo, x: i32) void {
|
||||||
*foo = Foo { .int = x };
|
foo.* = Foo{ .int = x };
|
||||||
}
|
}
|
||||||
|
|
||||||
const FooExtern = extern union {
|
const FooExtern = extern union {
|
||||||
@ -69,13 +72,12 @@ const FooExtern = extern union {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test "basic extern unions" {
|
test "basic extern unions" {
|
||||||
var foo = FooExtern { .int = 1 };
|
var foo = FooExtern{ .int = 1 };
|
||||||
assert(foo.int == 1);
|
assert(foo.int == 1);
|
||||||
foo.float = 12.34;
|
foo.float = 12.34;
|
||||||
assert(foo.float == 12.34);
|
assert(foo.float == 12.34);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Letter = enum {
|
const Letter = enum {
|
||||||
A,
|
A,
|
||||||
B,
|
B,
|
||||||
@ -93,12 +95,12 @@ test "union with specified enum tag" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn doTest() void {
|
fn doTest() void {
|
||||||
assert(bar(Payload {.A = 1234}) == -10);
|
assert(bar(Payload{ .A = 1234 }) == -10);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bar(value: &const Payload) i32 {
|
fn bar(value: &const Payload) i32 {
|
||||||
assert(Letter(*value) == Letter.A);
|
assert(Letter(value.*) == Letter.A);
|
||||||
return switch (*value) {
|
return switch (value.*) {
|
||||||
Payload.A => |x| return x - 1244,
|
Payload.A => |x| return x - 1244,
|
||||||
Payload.B => |x| if (x == 12.34) i32(20) else 21,
|
Payload.B => |x| if (x == 12.34) i32(20) else 21,
|
||||||
Payload.C => |x| if (x) i32(30) else 31,
|
Payload.C => |x| if (x) i32(30) else 31,
|
||||||
@ -131,13 +133,13 @@ const MultipleChoice2 = union(enum(u32)) {
|
|||||||
|
|
||||||
test "union(enum(u32)) with specified and unspecified tag values" {
|
test "union(enum(u32)) with specified and unspecified tag values" {
|
||||||
comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
|
comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
|
||||||
testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 {.C = 123});
|
testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
|
||||||
comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 { .C = 123} );
|
comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) void {
|
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) void {
|
||||||
assert(u32(@TagType(MultipleChoice2)(*x)) == 60);
|
assert(u32(@TagType(MultipleChoice2)(x.*)) == 60);
|
||||||
assert(1123 == switch (*x) {
|
assert(1123 == switch (x.*) {
|
||||||
MultipleChoice2.A => 1,
|
MultipleChoice2.A => 1,
|
||||||
MultipleChoice2.B => 2,
|
MultipleChoice2.B => 2,
|
||||||
MultipleChoice2.C => |v| i32(1000) + v,
|
MultipleChoice2.C => |v| i32(1000) + v,
|
||||||
@ -150,10 +152,9 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) void
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ExternPtrOrInt = extern union {
|
const ExternPtrOrInt = extern union {
|
||||||
ptr: &u8,
|
ptr: &u8,
|
||||||
int: u64
|
int: u64,
|
||||||
};
|
};
|
||||||
test "extern union size" {
|
test "extern union size" {
|
||||||
comptime assert(@sizeOf(ExternPtrOrInt) == 8);
|
comptime assert(@sizeOf(ExternPtrOrInt) == 8);
|
||||||
@ -161,7 +162,7 @@ test "extern union size" {
|
|||||||
|
|
||||||
const PackedPtrOrInt = packed union {
|
const PackedPtrOrInt = packed union {
|
||||||
ptr: &u8,
|
ptr: &u8,
|
||||||
int: u64
|
int: u64,
|
||||||
};
|
};
|
||||||
test "extern union size" {
|
test "extern union size" {
|
||||||
comptime assert(@sizeOf(PackedPtrOrInt) == 8);
|
comptime assert(@sizeOf(PackedPtrOrInt) == 8);
|
||||||
@ -174,8 +175,16 @@ test "union with only 1 field which is void should be zero bits" {
|
|||||||
comptime assert(@sizeOf(ZeroBits) == 0);
|
comptime assert(@sizeOf(ZeroBits) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TheTag = enum {A, B, C};
|
const TheTag = enum {
|
||||||
const TheUnion = union(TheTag) { A: i32, B: i32, C: i32 };
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
};
|
||||||
|
const TheUnion = union(TheTag) {
|
||||||
|
A: i32,
|
||||||
|
B: i32,
|
||||||
|
C: i32,
|
||||||
|
};
|
||||||
test "union field access gives the enum values" {
|
test "union field access gives the enum values" {
|
||||||
assert(TheUnion.A == TheTag.A);
|
assert(TheUnion.A == TheTag.A);
|
||||||
assert(TheUnion.B == TheTag.B);
|
assert(TheUnion.B == TheTag.B);
|
||||||
@ -183,20 +192,28 @@ test "union field access gives the enum values" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "cast union to tag type of union" {
|
test "cast union to tag type of union" {
|
||||||
testCastUnionToTagType(TheUnion {.B = 1234});
|
testCastUnionToTagType(TheUnion{ .B = 1234 });
|
||||||
comptime testCastUnionToTagType(TheUnion {.B = 1234});
|
comptime testCastUnionToTagType(TheUnion{ .B = 1234 });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testCastUnionToTagType(x: &const TheUnion) void {
|
fn testCastUnionToTagType(x: &const TheUnion) void {
|
||||||
assert(TheTag(*x) == TheTag.B);
|
assert(TheTag(x.*) == TheTag.B);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "cast tag type of union to union" {
|
test "cast tag type of union to union" {
|
||||||
var x: Value2 = Letter2.B;
|
var x: Value2 = Letter2.B;
|
||||||
assert(Letter2(x) == Letter2.B);
|
assert(Letter2(x) == Letter2.B);
|
||||||
}
|
}
|
||||||
const Letter2 = enum { A, B, C };
|
const Letter2 = enum {
|
||||||
const Value2 = union(Letter2) { A: i32, B, C, };
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
};
|
||||||
|
const Value2 = union(Letter2) {
|
||||||
|
A: i32,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
};
|
||||||
|
|
||||||
test "implicit cast union to its tag type" {
|
test "implicit cast union to its tag type" {
|
||||||
var x: Value2 = Letter2.B;
|
var x: Value2 = Letter2.B;
|
||||||
@ -217,19 +234,16 @@ const TheUnion2 = union(enum) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn assertIsTheUnion2Item1(value: &const TheUnion2) void {
|
fn assertIsTheUnion2Item1(value: &const TheUnion2) void {
|
||||||
assert(*value == TheUnion2.Item1);
|
assert(value.* == TheUnion2.Item1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub const PackThis = union(enum) {
|
pub const PackThis = union(enum) {
|
||||||
Invalid: bool,
|
Invalid: bool,
|
||||||
StringLiteral: u2,
|
StringLiteral: u2,
|
||||||
};
|
};
|
||||||
|
|
||||||
test "constant packed union" {
|
test "constant packed union" {
|
||||||
testConstPackedUnion([]PackThis {
|
testConstPackedUnion([]PackThis{PackThis{ .StringLiteral = 1 }});
|
||||||
PackThis { .StringLiteral = 1 },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testConstPackedUnion(expected_tokens: []const PackThis) void {
|
fn testConstPackedUnion(expected_tokens: []const PackThis) void {
|
||||||
@ -242,7 +256,7 @@ test "switch on union with only 1 field" {
|
|||||||
switch (r) {
|
switch (r) {
|
||||||
PartialInst.Compiled => {
|
PartialInst.Compiled => {
|
||||||
var z: PartialInstWithPayload = undefined;
|
var z: PartialInstWithPayload = undefined;
|
||||||
z = PartialInstWithPayload { .Compiled = 1234 };
|
z = PartialInstWithPayload{ .Compiled = 1234 };
|
||||||
switch (z) {
|
switch (z) {
|
||||||
PartialInstWithPayload.Compiled => |x| {
|
PartialInstWithPayload.Compiled => |x| {
|
||||||
assert(x == 1234);
|
assert(x == 1234);
|
||||||
@ -261,4 +275,3 @@ const PartialInst = union(enum) {
|
|||||||
const PartialInstWithPayload = union(enum) {
|
const PartialInstWithPayload = union(enum) {
|
||||||
Compiled: i32,
|
Compiled: i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,9 +2,12 @@ const assert = @import("std").debug.assert;
|
|||||||
|
|
||||||
fn add(args: ...) i32 {
|
fn add(args: ...) i32 {
|
||||||
var sum = i32(0);
|
var sum = i32(0);
|
||||||
{comptime var i: usize = 0; inline while (i < args.len) : (i += 1) {
|
{
|
||||||
sum += args[i];
|
comptime var i: usize = 0;
|
||||||
}}
|
inline while (i < args.len) : (i += 1) {
|
||||||
|
sum += args[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,18 +58,23 @@ fn extraFn(extra: u32, args: ...) usize {
|
|||||||
return args.len;
|
return args.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const foos = []fn(...) bool {
|
||||||
|
foo1,
|
||||||
|
foo2,
|
||||||
|
};
|
||||||
|
|
||||||
const foos = []fn(...) bool { foo1, foo2 };
|
fn foo1(args: ...) bool {
|
||||||
|
return true;
|
||||||
fn foo1(args: ...) bool { return true; }
|
}
|
||||||
fn foo2(args: ...) bool { return false; }
|
fn foo2(args: ...) bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
test "array of var args functions" {
|
test "array of var args functions" {
|
||||||
assert(foos[0]());
|
assert(foos[0]());
|
||||||
assert(!foos[1]());
|
assert(!foos[1]());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "pass array and slice of same array to var args should have same pointers" {
|
test "pass array and slice of same array to var args should have same pointers" {
|
||||||
const array = "hi";
|
const array = "hi";
|
||||||
const slice: []const u8 = array;
|
const slice: []const u8 = array;
|
||||||
@ -79,7 +87,6 @@ fn assertSlicePtrsEql(args: ...) void {
|
|||||||
assert(s1.ptr == s2.ptr);
|
assert(s1.ptr == s2.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "pass zero length array to var args param" {
|
test "pass zero length array to var args param" {
|
||||||
doNothingWithFirstArg("");
|
doNothingWithFirstArg("");
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const assert = @import("std").debug.assert;
|
const assert = @import("std").debug.assert;
|
||||||
|
|
||||||
test "while loop" {
|
test "while loop" {
|
||||||
var i : i32 = 0;
|
var i: i32 = 0;
|
||||||
while (i < 4) {
|
while (i < 4) {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ test "continue and break" {
|
|||||||
}
|
}
|
||||||
var continue_and_break_counter: i32 = 0;
|
var continue_and_break_counter: i32 = 0;
|
||||||
fn runContinueAndBreakTest() void {
|
fn runContinueAndBreakTest() void {
|
||||||
var i : i32 = 0;
|
var i: i32 = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
continue_and_break_counter += 2;
|
continue_and_break_counter += 2;
|
||||||
i += 1;
|
i += 1;
|
||||||
@ -58,10 +58,13 @@ fn returnWithImplicitCastFromWhileLoopTest() error!void {
|
|||||||
|
|
||||||
test "while with continue expression" {
|
test "while with continue expression" {
|
||||||
var sum: i32 = 0;
|
var sum: i32 = 0;
|
||||||
{var i: i32 = 0; while (i < 10) : (i += 1) {
|
{
|
||||||
if (i == 5) continue;
|
var i: i32 = 0;
|
||||||
sum += i;
|
while (i < 10) : (i += 1) {
|
||||||
}}
|
if (i == 5) continue;
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
}
|
||||||
assert(sum == 40);
|
assert(sum == 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,17 +120,13 @@ test "while with error union condition" {
|
|||||||
|
|
||||||
var numbers_left: i32 = undefined;
|
var numbers_left: i32 = undefined;
|
||||||
fn getNumberOrErr() error!i32 {
|
fn getNumberOrErr() error!i32 {
|
||||||
return if (numbers_left == 0)
|
return if (numbers_left == 0) error.OutOfNumbers else x: {
|
||||||
error.OutOfNumbers
|
|
||||||
else x: {
|
|
||||||
numbers_left -= 1;
|
numbers_left -= 1;
|
||||||
break :x numbers_left;
|
break :x numbers_left;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn getNumberOrNull() ?i32 {
|
fn getNumberOrNull() ?i32 {
|
||||||
return if (numbers_left == 0)
|
return if (numbers_left == 0) null else x: {
|
||||||
null
|
|
||||||
else x: {
|
|
||||||
numbers_left -= 1;
|
numbers_left -= 1;
|
||||||
break :x numbers_left;
|
break :x numbers_left;
|
||||||
};
|
};
|
||||||
@ -136,42 +135,48 @@ fn getNumberOrNull() ?i32 {
|
|||||||
test "while on nullable with else result follow else prong" {
|
test "while on nullable with else result follow else prong" {
|
||||||
const result = while (returnNull()) |value| {
|
const result = while (returnNull()) |value| {
|
||||||
break value;
|
break value;
|
||||||
} else i32(2);
|
} else
|
||||||
|
i32(2);
|
||||||
assert(result == 2);
|
assert(result == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "while on nullable with else result follow break prong" {
|
test "while on nullable with else result follow break prong" {
|
||||||
const result = while (returnMaybe(10)) |value| {
|
const result = while (returnMaybe(10)) |value| {
|
||||||
break value;
|
break value;
|
||||||
} else i32(2);
|
} else
|
||||||
|
i32(2);
|
||||||
assert(result == 10);
|
assert(result == 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "while on error union with else result follow else prong" {
|
test "while on error union with else result follow else prong" {
|
||||||
const result = while (returnError()) |value| {
|
const result = while (returnError()) |value| {
|
||||||
break value;
|
break value;
|
||||||
} else |err| i32(2);
|
} else|err|
|
||||||
|
i32(2);
|
||||||
assert(result == 2);
|
assert(result == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "while on error union with else result follow break prong" {
|
test "while on error union with else result follow break prong" {
|
||||||
const result = while (returnSuccess(10)) |value| {
|
const result = while (returnSuccess(10)) |value| {
|
||||||
break value;
|
break value;
|
||||||
} else |err| i32(2);
|
} else|err|
|
||||||
|
i32(2);
|
||||||
assert(result == 10);
|
assert(result == 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "while on bool with else result follow else prong" {
|
test "while on bool with else result follow else prong" {
|
||||||
const result = while (returnFalse()) {
|
const result = while (returnFalse()) {
|
||||||
break i32(10);
|
break i32(10);
|
||||||
} else i32(2);
|
} else
|
||||||
|
i32(2);
|
||||||
assert(result == 2);
|
assert(result == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "while on bool with else result follow break prong" {
|
test "while on bool with else result follow break prong" {
|
||||||
const result = while (returnTrue()) {
|
const result = while (returnTrue()) {
|
||||||
break i32(10);
|
break i32(10);
|
||||||
} else i32(2);
|
} else
|
||||||
|
i32(2);
|
||||||
assert(result == 10);
|
assert(result == 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,9 +207,21 @@ fn testContinueOuter() void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn returnNull() ?i32 { return null; }
|
fn returnNull() ?i32 {
|
||||||
fn returnMaybe(x: i32) ?i32 { return x; }
|
return null;
|
||||||
fn returnError() error!i32 { return error.YouWantedAnError; }
|
}
|
||||||
fn returnSuccess(x: i32) error!i32 { return x; }
|
fn returnMaybe(x: i32) ?i32 {
|
||||||
fn returnFalse() bool { return false; }
|
return x;
|
||||||
fn returnTrue() bool { return true; }
|
}
|
||||||
|
fn returnError() error!i32 {
|
||||||
|
return error.YouWantedAnError;
|
||||||
|
}
|
||||||
|
fn returnSuccess(x: i32) error!i32 {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
fn returnFalse() bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fn returnTrue() bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user