mirror of
https://github.com/ziglang/zig.git
synced 2025-02-14 16:40:17 +00:00
slice and array re-work plus some misc. changes
* `@truncate` builtin allows casting to the same size integer. It also performs two's complement casting between signed and unsigned integers. * The idiomatic way to convert between bytes and numbers is now `mem.readInt` and `mem.writeInt` instead of an unsafe cast. It works at compile time, is safer, and looks cleaner. * Implicitly casting an array to a slice is allowed only if the slice is const. * Constant pointer values know if their memory is from a compile- time constant value or a compile-time variable. * Cast from [N]u8 to []T no longer allowed, but [N]u8 to []const T still allowed. * Fix inability to pass a mutable pointer to comptime variable at compile-time to a function and have the function modify the memory pointed to by the pointer. * Add the `comptime T: type` parameter back to mem.eql. Prevents accidentally creating instantiations for arrays.
This commit is contained in:
parent
ca180d3f02
commit
6dba1f1c8e
@ -637,6 +637,25 @@ const b: u8 = @truncate(u8, a);
|
||||
// b is now 0xcd
|
||||
```
|
||||
|
||||
This function always truncates the significant bits of the integer, regardless
|
||||
of endianness on the target platform.
|
||||
|
||||
This function also performs a twos complement cast. For example, the following
|
||||
produces a crash in debug mode and undefined behavior in release mode:
|
||||
|
||||
```zig
|
||||
const a = i16(-1);
|
||||
const b = u16(a);
|
||||
```
|
||||
|
||||
However this is well defined and working code:
|
||||
|
||||
```zig
|
||||
const a = i16(-1);
|
||||
const b = @truncate(u16, a);
|
||||
// b is now 0xffff
|
||||
```
|
||||
|
||||
### @compileError(comptime msg: []u8)
|
||||
|
||||
This function, when semantically analyzed, causes a compile error with the
|
||||
|
@ -6,10 +6,11 @@ const os = std.os;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
%%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");
|
||||
|
||||
var seed: [@sizeOf(usize)]u8 = undefined;
|
||||
%%os.getRandomBytes(seed);
|
||||
var seed_bytes: [@sizeOf(usize)]u8 = undefined;
|
||||
%%os.getRandomBytes(seed_bytes[0...]);
|
||||
const seed = std.mem.readInt(seed_bytes, usize, true);
|
||||
var rand: Rand = undefined;
|
||||
rand.init(([]usize)(seed)[0]);
|
||||
rand.init(seed);
|
||||
|
||||
const answer = rand.rangeUnsigned(u8, 0, 100) + 1;
|
||||
|
||||
|
@ -119,11 +119,21 @@ enum ConstPtrSpecial {
|
||||
ConstPtrSpecialHardCodedAddr,
|
||||
};
|
||||
|
||||
struct ConstPtrValue {
|
||||
ConstPtrSpecial special;
|
||||
enum ConstPtrMut {
|
||||
// The pointer points to memory that is known at compile time and immutable.
|
||||
ConstPtrMutComptimeConst,
|
||||
// This means that the pointer points to memory used by a comptime variable,
|
||||
// so attempting to write a non-compile-time known value is an error
|
||||
bool comptime_var_mem;
|
||||
// But the underlying value is allowed to change at compile time.
|
||||
ConstPtrMutComptimeVar,
|
||||
// The pointer points to memory that is known only at runtime.
|
||||
// For example it may point to the initializer value of a variable.
|
||||
ConstPtrMutRuntimeVar,
|
||||
};
|
||||
|
||||
struct ConstPtrValue {
|
||||
ConstPtrSpecial special;
|
||||
ConstPtrMut mut;
|
||||
|
||||
union {
|
||||
struct {
|
||||
|
@ -2833,7 +2833,18 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
||||
const_val->data.x_arg_tuple.end_index * 2290442768;
|
||||
case TypeTableEntryIdPointer:
|
||||
{
|
||||
uint32_t hash_val = const_val->data.x_ptr.comptime_var_mem ? 2216297012 : 170810250;
|
||||
uint32_t hash_val = 0;
|
||||
switch (const_val->data.x_ptr.mut) {
|
||||
case ConstPtrMutRuntimeVar:
|
||||
hash_val += 3500721036;
|
||||
break;
|
||||
case ConstPtrMutComptimeConst:
|
||||
hash_val += 4214318515;
|
||||
break;
|
||||
case ConstPtrMutComptimeVar:
|
||||
hash_val += 1103195694;
|
||||
break;
|
||||
}
|
||||
switch (const_val->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
zig_unreachable();
|
||||
@ -3339,7 +3350,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
||||
case TypeTableEntryIdPointer:
|
||||
if (a->data.x_ptr.special != b->data.x_ptr.special)
|
||||
return false;
|
||||
if (a->data.x_ptr.comptime_var_mem != b->data.x_ptr.comptime_var_mem)
|
||||
if (a->data.x_ptr.mut != b->data.x_ptr.mut)
|
||||
return false;
|
||||
switch (a->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
|
@ -1859,9 +1859,18 @@ static LLVMValueRef ir_render_div_exact(CodeGen *g, IrExecutable *executable, Ir
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrInstructionTruncate *instruction) {
|
||||
TypeTableEntry *dest_type = get_underlying_type(instruction->base.value.type);
|
||||
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
|
||||
return LLVMBuildTrunc(g->builder, target_val, dest_type->type_ref, "");
|
||||
TypeTableEntry *dest_type = get_underlying_type(instruction->base.value.type);
|
||||
TypeTableEntry *src_type = get_underlying_type(instruction->target->value.type);
|
||||
if (dest_type == src_type) {
|
||||
// no-op
|
||||
return target_val;
|
||||
} if (src_type->data.integral.bit_count == dest_type->data.integral.bit_count) {
|
||||
return LLVMBuildBitCast(g->builder, target_val, dest_type->type_ref, "");
|
||||
} else {
|
||||
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
|
||||
return LLVMBuildTrunc(g->builder, target_val, dest_type->type_ref, "");
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrInstructionAlloca *instruction) {
|
||||
@ -1945,10 +1954,14 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
|
||||
static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) {
|
||||
assert(instruction->tmp_ptr);
|
||||
|
||||
TypeTableEntry *array_type = get_underlying_type(instruction->ptr->value.type);
|
||||
LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr);
|
||||
TypeTableEntry *array_ptr_type = instruction->ptr->value.type;
|
||||
assert(array_ptr_type->id == TypeTableEntryIdPointer);
|
||||
bool is_volatile = array_ptr_type->data.pointer.is_volatile;
|
||||
TypeTableEntry *array_type = array_ptr_type->data.pointer.child_type;
|
||||
LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, is_volatile);
|
||||
|
||||
LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
|
||||
LLVMValueRef array_ptr = ir_llvm_value(g, instruction->ptr);
|
||||
|
||||
bool want_debug_safety = instruction->safety_check_on && ir_want_debug_safety(g, &instruction->base);
|
||||
|
||||
@ -2582,7 +2595,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
|
||||
return LLVMGetUndef(canon_type->type_ref);
|
||||
case ConstValSpecialStatic:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
switch (canon_type->id) {
|
||||
|
262
src/ir.cpp
262
src/ir.cpp
@ -1480,15 +1480,6 @@ static IrInstruction *ir_build_ref(IrBuilder *irb, Scope *scope, AstNode *source
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value,
|
||||
bool is_const, bool is_volatile)
|
||||
{
|
||||
IrInstruction *new_instruction = ir_build_ref(irb, old_instruction->scope, old_instruction->source_node,
|
||||
value, is_const, is_volatile);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_min_value(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
|
||||
IrInstructionMinValue *instruction = ir_build_instruction<IrInstructionMinValue>(irb, scope, source_node);
|
||||
instruction->value = value;
|
||||
@ -5290,7 +5281,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node)
|
||||
AstNode *start_node = slice_expr->start;
|
||||
AstNode *end_node = slice_expr->end;
|
||||
|
||||
IrInstruction *ptr_value = ir_gen_node(irb, array_node, scope);
|
||||
IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LVAL_PTR);
|
||||
if (ptr_value == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
@ -5822,12 +5813,16 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
|
||||
// implicit array to slice conversion
|
||||
if (expected_type->id == TypeTableEntryIdStruct &&
|
||||
expected_type->data.structure.is_slice &&
|
||||
actual_type->id == TypeTableEntryIdArray &&
|
||||
types_match_const_cast_only(
|
||||
expected_type->data.structure.fields[0].type_entry->data.pointer.child_type,
|
||||
actual_type->data.array.child_type))
|
||||
actual_type->id == TypeTableEntryIdArray)
|
||||
{
|
||||
return ImplicitCastMatchResultYes;
|
||||
TypeTableEntry *ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
|
||||
if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
|
||||
types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
|
||||
{
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
}
|
||||
|
||||
// implicit number literal to typed number
|
||||
@ -6180,7 +6175,7 @@ static TypeTableEntry *ir_finish_anal(IrAnalyze *ira, TypeTableEntry *result_typ
|
||||
return result_type;
|
||||
}
|
||||
|
||||
static ConstExprValue *ir_build_const_from(IrAnalyze *ira, IrInstruction *old_instruction) {
|
||||
static IrInstruction *ir_get_const(IrAnalyze *ira, IrInstruction *old_instruction) {
|
||||
IrInstruction *new_instruction;
|
||||
if (old_instruction->id == IrInstructionIdVarPtr) {
|
||||
IrInstructionVarPtr *old_var_ptr_instruction = (IrInstructionVarPtr *)old_instruction;
|
||||
@ -6201,10 +6196,14 @@ static ConstExprValue *ir_build_const_from(IrAnalyze *ira, IrInstruction *old_in
|
||||
old_instruction->scope, old_instruction->source_node);
|
||||
new_instruction = &const_instruction->base;
|
||||
}
|
||||
new_instruction->value.special = ConstValSpecialStatic;
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static ConstExprValue *ir_build_const_from(IrAnalyze *ira, IrInstruction *old_instruction) {
|
||||
IrInstruction *new_instruction = ir_get_const(ira, old_instruction);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
ConstExprValue *const_val = &new_instruction->value;
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
return const_val;
|
||||
return &new_instruction->value;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_void(IrAnalyze *ira, IrInstruction *instruction) {
|
||||
@ -6212,33 +6211,47 @@ static TypeTableEntry *ir_analyze_void(IrAnalyze *ira, IrInstruction *instructio
|
||||
return ira->codegen->builtin_types.entry_void;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
||||
static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
||||
ConstExprValue *pointee, TypeTableEntry *pointee_type,
|
||||
bool comptime_var_mem, bool ptr_is_const, bool ptr_is_volatile)
|
||||
ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile)
|
||||
{
|
||||
if (pointee_type->id == TypeTableEntryIdMetaType) {
|
||||
TypeTableEntry *type_entry = pointee->data.x_type;
|
||||
if (type_entry->id == TypeTableEntryIdUnreachable) {
|
||||
ir_add_error(ira, instruction, buf_sprintf("pointer to unreachable not allowed"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
ConstExprValue *const_val = ir_build_const_from(ira, instruction);
|
||||
IrInstruction *const_instr = ir_get_const(ira, instruction);
|
||||
ConstExprValue *const_val = &const_instr->value;
|
||||
const_val->type = pointee_type;
|
||||
type_ensure_zero_bits_known(ira->codegen, type_entry);
|
||||
const_val->data.x_type = get_pointer_to_type_volatile(ira->codegen, type_entry,
|
||||
ptr_is_const, ptr_is_volatile);
|
||||
return pointee_type;
|
||||
return const_instr;
|
||||
} else {
|
||||
TypeTableEntry *ptr_type = get_pointer_to_type_volatile(ira->codegen, pointee_type,
|
||||
ptr_is_const, ptr_is_volatile);
|
||||
ConstExprValue *const_val = ir_build_const_from(ira, instruction);
|
||||
IrInstruction *const_instr = ir_get_const(ira, instruction);
|
||||
ConstExprValue *const_val = &const_instr->value;
|
||||
const_val->type = ptr_type;
|
||||
const_val->data.x_ptr.special = ConstPtrSpecialRef;
|
||||
const_val->data.x_ptr.comptime_var_mem = comptime_var_mem;
|
||||
const_val->data.x_ptr.mut = ptr_mut;
|
||||
const_val->data.x_ptr.data.ref.pointee = pointee;
|
||||
return ptr_type;
|
||||
return const_instr;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
||||
ConstExprValue *pointee, TypeTableEntry *pointee_type,
|
||||
ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile)
|
||||
{
|
||||
IrInstruction *const_instr = ir_get_const_ptr(ira, instruction, pointee,
|
||||
pointee_type, ptr_mut, ptr_is_const, ptr_is_volatile);
|
||||
ir_link_new_instruction(const_instr, instruction);
|
||||
return const_instr->value.type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *instruction, uint64_t value) {
|
||||
ConstExprValue *const_val = ir_build_const_from(ira, instruction);
|
||||
bignum_init_unsigned(&const_val->data.x_bignum, value);
|
||||
@ -6513,6 +6526,37 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value,
|
||||
bool is_const, bool is_volatile)
|
||||
{
|
||||
if (value->value.type->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (value->id == IrInstructionIdLoadPtr) {
|
||||
IrInstructionLoadPtr *load_ptr_inst = (IrInstructionLoadPtr *) value;
|
||||
if (load_ptr_inst->ptr->value.type->data.pointer.is_const) {
|
||||
return load_ptr_inst->ptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
|
||||
if (!val)
|
||||
return ira->codegen->invalid_instruction;
|
||||
return ir_get_const_ptr(ira, source_instruction, val, value->value.type,
|
||||
ConstPtrMutComptimeConst, is_const, is_volatile);
|
||||
}
|
||||
|
||||
TypeTableEntry *ptr_type = get_pointer_to_type_volatile(ira->codegen, value->value.type, is_const, is_volatile);
|
||||
FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
|
||||
assert(fn_entry);
|
||||
IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
|
||||
source_instruction->source_node, value, is_const, is_volatile);
|
||||
new_instruction->value.type = ptr_type;
|
||||
fn_entry->alloca_list.append(new_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *array, TypeTableEntry *wanted_type)
|
||||
{
|
||||
@ -6536,19 +6580,14 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
|
||||
source_instr->source_node, ira->codegen->builtin_types.entry_usize);
|
||||
init_const_usize(ira->codegen, &end->value, array_type->data.array.len);
|
||||
|
||||
bool is_const;
|
||||
if (array->id == IrInstructionIdLoadPtr) {
|
||||
IrInstructionLoadPtr *load_ptr_inst = (IrInstructionLoadPtr *) array;
|
||||
is_const = load_ptr_inst->ptr->value.type->data.pointer.is_const;
|
||||
} else {
|
||||
is_const = true;
|
||||
}
|
||||
IrInstruction *array_ptr = ir_get_ref(ira, source_instr, array, true, false);
|
||||
|
||||
IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, array, start, end, is_const, false);
|
||||
source_instr->source_node, array_ptr, start, end, false, false);
|
||||
TypeTableEntry *child_type = array_type->data.array.child_type;
|
||||
result->value.type = get_slice_type(ira->codegen, child_type, is_const);
|
||||
result->value.type = get_slice_type(ira->codegen, child_type, true);
|
||||
ir_add_alloca(ira, result, result->value.type);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -6780,29 +6819,31 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
}
|
||||
|
||||
// explicit cast from array to slice
|
||||
if (is_slice(wanted_type) &&
|
||||
actual_type->id == TypeTableEntryIdArray &&
|
||||
types_match_const_cast_only(
|
||||
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
|
||||
actual_type->data.array.child_type))
|
||||
{
|
||||
return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
|
||||
if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
|
||||
TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
|
||||
types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
|
||||
{
|
||||
return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
}
|
||||
|
||||
// explicit cast from []T to []u8 or []u8 to []T
|
||||
if (is_slice(wanted_type) && is_slice(actual_type) &&
|
||||
(is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) ||
|
||||
is_u8(actual_type->data.structure.fields[0].type_entry->data.pointer.child_type)) &&
|
||||
(wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
|
||||
!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
|
||||
(is_u8(wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type) ||
|
||||
is_u8(actual_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type)) &&
|
||||
(wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
|
||||
!actual_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const))
|
||||
{
|
||||
if (!ir_emit_global_runtime_side_effect(ira, source_instr))
|
||||
return ira->codegen->invalid_instruction;
|
||||
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpResizeSlice, true);
|
||||
}
|
||||
|
||||
// explicit cast from [N]u8 to []T
|
||||
// explicit cast from [N]u8 to []const T
|
||||
if (is_slice(wanted_type) &&
|
||||
wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const &&
|
||||
actual_type->id == TypeTableEntryIdArray &&
|
||||
is_u8(actual_type->data.array.child_type))
|
||||
{
|
||||
@ -7010,9 +7051,9 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
|
||||
} else if (type_entry->id == TypeTableEntryIdPointer) {
|
||||
TypeTableEntry *child_type = type_entry->data.pointer.child_type;
|
||||
if (instr_is_comptime(ptr)) {
|
||||
// Dereferencing a mutable pointer at compile time is not allowed
|
||||
// unless that pointer is from a comptime variable
|
||||
if (type_entry->data.pointer.is_const || ptr->value.data.x_ptr.comptime_var_mem) {
|
||||
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
|
||||
ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
|
||||
{
|
||||
ConstExprValue *pointee = const_ptr_pointee(&ptr->value);
|
||||
if (pointee->special != ConstValSpecialRuntime) {
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
|
||||
@ -7053,23 +7094,9 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
|
||||
static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value,
|
||||
bool is_const, bool is_volatile)
|
||||
{
|
||||
if (value->value.type->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
|
||||
if (!val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
return ir_analyze_const_ptr(ira, source_instruction, val, value->value.type, false, is_const, is_volatile);
|
||||
}
|
||||
|
||||
TypeTableEntry *ptr_type = get_pointer_to_type_volatile(ira->codegen, value->value.type, is_const, is_volatile);
|
||||
FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
|
||||
assert(fn_entry);
|
||||
IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction,
|
||||
value, is_const, is_volatile);
|
||||
fn_entry->alloca_list.append(new_instruction);
|
||||
return ptr_type;
|
||||
IrInstruction *result = ir_get_ref(ira, source_instruction, value, is_const, is_volatile);
|
||||
ir_link_new_instruction(result, source_instruction);
|
||||
return result->value.type;
|
||||
}
|
||||
|
||||
static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) {
|
||||
@ -8747,8 +8774,16 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc
|
||||
bool is_const = (var->value.type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
|
||||
bool is_volatile = (var->value.type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
|
||||
if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
|
||||
return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value.type,
|
||||
comptime_var_mem, is_const, is_volatile);
|
||||
ConstPtrMut ptr_mut;
|
||||
if (comptime_var_mem) {
|
||||
ptr_mut = ConstPtrMutComptimeVar;
|
||||
} else if (var->gen_is_const) {
|
||||
ptr_mut = ConstPtrMutComptimeConst;
|
||||
} else {
|
||||
assert(!comptime_var_mem);
|
||||
ptr_mut = ConstPtrMutRuntimeVar;
|
||||
}
|
||||
return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value.type, ptr_mut, is_const, is_volatile);
|
||||
} else {
|
||||
ir_build_var_ptr_from(&ira->new_irb, instruction, var, is_const, is_volatile);
|
||||
type_ensure_zero_bits_known(ira->codegen, var->value.type);
|
||||
@ -8837,7 +8872,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
|
||||
is_const, is_volatile);
|
||||
} else {
|
||||
return ir_analyze_const_ptr(ira, &elem_ptr_instruction->base, &ira->codegen->const_void_val,
|
||||
ira->codegen->builtin_types.entry_void, false, is_const, is_volatile);
|
||||
ira->codegen->builtin_types.entry_void, ConstPtrMutComptimeConst, is_const, is_volatile);
|
||||
}
|
||||
} else {
|
||||
ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
|
||||
@ -8872,8 +8907,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
|
||||
array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))
|
||||
{
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
|
||||
out_val->data.x_ptr.comptime_var_mem = array_ptr->value.data.x_ptr.comptime_var_mem;
|
||||
if (array_type->id == TypeTableEntryIdPointer) {
|
||||
out_val->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
|
||||
size_t new_index;
|
||||
size_t mem_size;
|
||||
size_t old_size;
|
||||
@ -8926,6 +8961,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
|
||||
index, slice_len));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
out_val->data.x_ptr.mut = ptr_field->data.x_ptr.mut;
|
||||
switch (ptr_field->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
zig_unreachable();
|
||||
@ -8953,6 +8989,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
|
||||
}
|
||||
} else if (array_type->id == TypeTableEntryIdArray) {
|
||||
out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
|
||||
out_val->data.x_ptr.mut = array_ptr->value.data.x_ptr.mut;
|
||||
out_val->data.x_ptr.data.base_array.array_val = array_ptr_val;
|
||||
out_val->data.x_ptr.data.base_array.elem_index = index;
|
||||
} else {
|
||||
@ -9023,7 +9060,7 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
|
||||
is_const, is_volatile);
|
||||
ConstExprValue *const_val = ir_build_const_from(ira, &field_ptr_instruction->base);
|
||||
const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
|
||||
const_val->data.x_ptr.comptime_var_mem = container_ptr->value.data.x_ptr.comptime_var_mem;
|
||||
const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
|
||||
const_val->data.x_ptr.data.base_struct.struct_val = struct_val;
|
||||
const_val->data.x_ptr.data.base_struct.field_index = field->src_index;
|
||||
return ptr_type;
|
||||
@ -9088,7 +9125,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry,
|
||||
false, ptr_is_const, ptr_is_volatile);
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
}
|
||||
case TldIdTypeDef:
|
||||
{
|
||||
@ -9105,7 +9142,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, source_instruction, const_val, ira->codegen->builtin_types.entry_type,
|
||||
false, ptr_is_const, ptr_is_volatile);
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -9148,7 +9185,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
|
||||
usize, false, ptr_is_const, ptr_is_volatile);
|
||||
usize, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else {
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
|
||||
@ -9172,7 +9209,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
|
||||
usize, false, ptr_is_const, ptr_is_volatile);
|
||||
usize, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else {
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
|
||||
@ -9211,14 +9248,14 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_enum_tag(child_type, field->value), child_type,
|
||||
false, ptr_is_const, ptr_is_volatile);
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_unsigned_negative(child_type->data.enumeration.tag_type, field->value, false),
|
||||
child_type->data.enumeration.tag_type,
|
||||
false, ptr_is_const, ptr_is_volatile);
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9243,7 +9280,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
|
||||
child_type, false, ptr_is_const, ptr_is_volatile);
|
||||
child_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
}
|
||||
|
||||
ir_add_error(ira, &field_ptr_instruction->base,
|
||||
@ -9257,14 +9294,14 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
create_const_unsigned_negative(ira->codegen->builtin_types.entry_num_lit_int,
|
||||
child_type->data.integral.bit_count, false),
|
||||
ira->codegen->builtin_types.entry_num_lit_int,
|
||||
false, ptr_is_const, ptr_is_volatile);
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else if (buf_eql_str(field_name, "is_signed")) {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_bool(ira->codegen, child_type->data.integral.is_signed),
|
||||
ira->codegen->builtin_types.entry_bool,
|
||||
false, ptr_is_const, ptr_is_volatile);
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else {
|
||||
ir_add_error(ira, &field_ptr_instruction->base,
|
||||
buf_sprintf("type '%s' has no member called '%s'",
|
||||
@ -9352,8 +9389,8 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
|
||||
bool comptime_var_mem = ptr->value.data.x_ptr.comptime_var_mem;
|
||||
if (comptime_var_mem) {
|
||||
assert(ptr->value.data.x_ptr.mut != ConstPtrMutComptimeConst);
|
||||
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
|
||||
if (instr_is_comptime(casted_value)) {
|
||||
ConstExprValue *dest_val = const_ptr_pointee(&ptr->value);
|
||||
if (dest_val->special != ConstValSpecialRuntime) {
|
||||
@ -11170,8 +11207,8 @@ static TypeTableEntry *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruc
|
||||
ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name)));
|
||||
// TODO if meta_type is type decl, add note pointing to type decl declaration
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else if (canon_src_type->data.integral.bit_count <= canon_dest_type->data.integral.bit_count) {
|
||||
ir_add_error(ira, target, buf_sprintf("type '%s' has same or fewer bits than destination type '%s'",
|
||||
} else if (canon_src_type->data.integral.bit_count < canon_dest_type->data.integral.bit_count) {
|
||||
ir_add_error(ira, target, buf_sprintf("type '%s' has fewer bits than destination type '%s'",
|
||||
buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
|
||||
// TODO if meta_type is type decl, add note pointing to type decl declaration
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@ -11457,10 +11494,15 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice *instruction) {
|
||||
IrInstruction *ptr = instruction->ptr->other;
|
||||
if (ptr->value.type->id == TypeTableEntryIdInvalid)
|
||||
IrInstruction *ptr_ptr = instruction->ptr->other;
|
||||
if (ptr_ptr->value.type->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
TypeTableEntry *ptr_type = ptr_ptr->value.type;
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *non_canon_array_type = ptr_type->data.pointer.child_type;
|
||||
TypeTableEntry *canon_array_type = get_underlying_type(non_canon_array_type);
|
||||
|
||||
IrInstruction *start = instruction->start->other;
|
||||
if (start->value.type->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@ -11482,44 +11524,42 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
|
||||
end = nullptr;
|
||||
}
|
||||
|
||||
TypeTableEntry *array_type = get_underlying_type(ptr->value.type);
|
||||
|
||||
TypeTableEntry *return_type;
|
||||
|
||||
if (array_type->id == TypeTableEntryIdArray) {
|
||||
return_type = get_slice_type(ira->codegen, array_type->data.array.child_type, instruction->is_const);
|
||||
} else if (array_type->id == TypeTableEntryIdPointer) {
|
||||
return_type = get_slice_type(ira->codegen, array_type->data.pointer.child_type, instruction->is_const);
|
||||
if (canon_array_type->id == TypeTableEntryIdArray) {
|
||||
return_type = get_slice_type(ira->codegen, canon_array_type->data.array.child_type, instruction->is_const);
|
||||
} else if (canon_array_type->id == TypeTableEntryIdPointer) {
|
||||
return_type = get_slice_type(ira->codegen, canon_array_type->data.pointer.child_type, instruction->is_const);
|
||||
if (!end) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (is_slice(array_type)) {
|
||||
} else if (is_slice(canon_array_type)) {
|
||||
return_type = get_slice_type(ira->codegen,
|
||||
array_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
|
||||
canon_array_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
|
||||
instruction->is_const);
|
||||
} else {
|
||||
ir_add_error(ira, &instruction->base,
|
||||
buf_sprintf("slice of non-array type '%s'", buf_ptr(&ptr->value.type->name)));
|
||||
buf_sprintf("slice of non-array type '%s'", buf_ptr(&non_canon_array_type->name)));
|
||||
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (ptr->value.special == ConstValSpecialStatic &&
|
||||
casted_start->value.special == ConstValSpecialStatic &&
|
||||
(!end || end->value.special == ConstValSpecialStatic))
|
||||
if (instr_is_comptime(ptr_ptr) &&
|
||||
value_is_comptime(&casted_start->value) &&
|
||||
(!end || value_is_comptime(&end->value)))
|
||||
{
|
||||
ConstExprValue *array_val;
|
||||
ConstExprValue *parent_ptr;
|
||||
size_t abs_offset;
|
||||
size_t rel_end;
|
||||
if (array_type->id == TypeTableEntryIdArray) {
|
||||
array_val = &ptr->value;
|
||||
if (canon_array_type->id == TypeTableEntryIdArray) {
|
||||
array_val = const_ptr_pointee(&ptr_ptr->value);
|
||||
abs_offset = 0;
|
||||
rel_end = array_type->data.array.len;
|
||||
rel_end = canon_array_type->data.array.len;
|
||||
parent_ptr = nullptr;
|
||||
} else if (array_type->id == TypeTableEntryIdPointer) {
|
||||
parent_ptr = &ptr->value;
|
||||
} else if (canon_array_type->id == TypeTableEntryIdPointer) {
|
||||
parent_ptr = const_ptr_pointee(&ptr_ptr->value);
|
||||
switch (parent_ptr->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
zig_unreachable();
|
||||
@ -11539,9 +11579,10 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
|
||||
array_val = nullptr;
|
||||
break;
|
||||
}
|
||||
} else if (is_slice(array_type)) {
|
||||
parent_ptr = &ptr->value.data.x_struct.fields[slice_ptr_index];
|
||||
ConstExprValue *len_val = &ptr->value.data.x_struct.fields[slice_len_index];
|
||||
} else if (is_slice(canon_array_type)) {
|
||||
ConstExprValue *slice_ptr = const_ptr_pointee(&ptr_ptr->value);
|
||||
parent_ptr = &slice_ptr->data.x_struct.fields[slice_ptr_index];
|
||||
ConstExprValue *len_val = &slice_ptr->data.x_struct.fields[slice_len_index];
|
||||
|
||||
switch (parent_ptr->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
@ -11596,6 +11637,9 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
|
||||
if (array_val) {
|
||||
size_t index = abs_offset + start_scalar;
|
||||
init_const_ptr_array(ira->codegen, ptr_val, array_val, index, instruction->is_const);
|
||||
if (canon_array_type->id == TypeTableEntryIdArray) {
|
||||
ptr_val->data.x_ptr.mut = ptr_ptr->value.data.x_ptr.mut;
|
||||
}
|
||||
} else {
|
||||
switch (parent_ptr->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
@ -11620,7 +11664,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
|
||||
}
|
||||
}
|
||||
|
||||
IrInstruction *new_instruction = ir_build_slice_from(&ira->new_irb, &instruction->base, ptr,
|
||||
IrInstruction *new_instruction = ir_build_slice_from(&ira->new_irb, &instruction->base, ptr_ptr,
|
||||
casted_start, end, instruction->is_const, instruction->safety_check_on);
|
||||
ir_add_alloca(ira, new_instruction, return_type);
|
||||
|
||||
|
@ -149,7 +149,7 @@ const Constant = struct {
|
||||
return error.InvalidDebugInfo;
|
||||
if (self.signed)
|
||||
return error.InvalidDebugInfo;
|
||||
return mem.sliceAsInt(self.payload, false, u64);
|
||||
return mem.readInt(self.payload, u64, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -93,8 +93,8 @@ pub const Elf = struct {
|
||||
elf.auto_close_stream = false;
|
||||
|
||||
var magic: [4]u8 = undefined;
|
||||
%return elf.in_stream.readNoEof(magic);
|
||||
if (!mem.eql(magic, "\x7fELF")) return error.InvalidFormat;
|
||||
%return elf.in_stream.readNoEof(magic[0...]);
|
||||
if (!mem.eql(u8, magic, "\x7fELF")) return error.InvalidFormat;
|
||||
|
||||
elf.is_64 = switch (%return elf.in_stream.readByte()) {
|
||||
1 => false,
|
||||
@ -236,7 +236,7 @@ pub const Elf = struct {
|
||||
elf.in_stream.close();
|
||||
}
|
||||
|
||||
pub fn findSection(elf: &Elf, name: []u8) -> %?&SectionHeader {
|
||||
pub fn findSection(elf: &Elf, name: []const u8) -> %?&SectionHeader {
|
||||
for (elf.section_headers) |*section| {
|
||||
if (section.sh_type == SHT_NULL) continue;
|
||||
|
||||
|
@ -1,21 +1,19 @@
|
||||
pub inline fn swapIfLe(comptime T: type, x: T) -> T {
|
||||
const mem = @import("mem.zig");
|
||||
|
||||
pub fn swapIfLe(comptime T: type, x: T) -> T {
|
||||
swapIf(false, T, x)
|
||||
}
|
||||
|
||||
pub inline fn swapIfBe(comptime T: type, x: T) -> T {
|
||||
pub fn swapIfBe(comptime T: type, x: T) -> T {
|
||||
swapIf(true, T, x)
|
||||
}
|
||||
|
||||
pub inline fn swapIf(is_be: bool, comptime T: type, x: T) -> T {
|
||||
pub fn swapIf(is_be: bool, comptime T: type, x: T) -> T {
|
||||
if (@compileVar("is_big_endian") == is_be) swap(T, x) else x
|
||||
}
|
||||
|
||||
pub fn swap(comptime T: type, x: T) -> T {
|
||||
const x_slice = ([]u8)((&const x)[0...1]);
|
||||
var result: T = undefined;
|
||||
const result_slice = ([]u8)((&result)[0...1]);
|
||||
for (result_slice) |*b, i| {
|
||||
*b = x_slice[@sizeOf(T) - i - 1];
|
||||
}
|
||||
return result;
|
||||
var buf: [@sizeOf(T)]u8 = undefined;
|
||||
mem.writeInt(buf[0...], x, false);
|
||||
return mem.readInt(buf, T, true);
|
||||
}
|
||||
|
35
std/io.zig
35
std/io.zig
@ -6,7 +6,6 @@ const system = switch(@compileVar("os")) {
|
||||
|
||||
const errno = @import("errno.zig");
|
||||
const math = @import("math.zig");
|
||||
const endian = @import("endian.zig");
|
||||
const debug = @import("debug.zig");
|
||||
const assert = debug.assert;
|
||||
const os = @import("os.zig");
|
||||
@ -365,7 +364,7 @@ pub const InStream = struct {
|
||||
|
||||
pub fn readByte(is: &InStream) -> %u8 {
|
||||
var result: [1]u8 = undefined;
|
||||
%return is.readNoEof(result);
|
||||
%return is.readNoEof(result[0...]);
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@ -378,10 +377,9 @@ pub const InStream = struct {
|
||||
}
|
||||
|
||||
pub fn readInt(is: &InStream, is_be: bool, comptime T: type) -> %T {
|
||||
var result: T = undefined;
|
||||
const result_slice = ([]u8)((&result)[0...1]);
|
||||
%return is.readNoEof(result_slice);
|
||||
return endian.swapIf(!is_be, T, result);
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
%return is.readNoEof(bytes[0...]);
|
||||
return mem.readInt(bytes, T, is_be);
|
||||
}
|
||||
|
||||
pub fn readVarInt(is: &InStream, is_be: bool, comptime T: type, size: usize) -> %T {
|
||||
@ -390,7 +388,7 @@ pub const InStream = struct {
|
||||
var input_buf: [8]u8 = undefined;
|
||||
const input_slice = input_buf[0...size];
|
||||
%return is.readNoEof(input_slice);
|
||||
return mem.sliceAsInt(input_slice, is_be, T);
|
||||
return mem.readInt(input_slice, T, is_be);
|
||||
}
|
||||
|
||||
pub fn seekForward(is: &InStream, amount: usize) -> %void {
|
||||
@ -589,18 +587,19 @@ fn testParseUnsignedComptime() {
|
||||
fn testBufPrintInt() {
|
||||
@setFnTest(this);
|
||||
|
||||
var buf: [max_int_digits]u8 = undefined;
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
|
||||
var buffer: [max_int_digits]u8 = undefined;
|
||||
const buf = buffer[0...];
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
|
||||
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
|
||||
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
|
||||
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
|
||||
assert(mem.eql(bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
|
||||
}
|
||||
|
103
std/mem.zig
103
std/mem.zig
@ -68,25 +68,8 @@ pub fn cmp(comptime T: type, a: []const T, b: []const T) -> Cmp {
|
||||
return if (a.len > b.len) Cmp.Greater else if (a.len < b.len) Cmp.Less else Cmp.Equal;
|
||||
}
|
||||
|
||||
pub fn sliceAsInt(buf: []u8, is_be: bool, comptime T: type) -> T {
|
||||
var result: T = undefined;
|
||||
const result_slice = ([]u8)((&result)[0...1]);
|
||||
set(u8, result_slice, 0);
|
||||
const padding = @sizeOf(T) - buf.len;
|
||||
|
||||
if (is_be == @compileVar("is_big_endian")) {
|
||||
copy(u8, result_slice, buf);
|
||||
} else {
|
||||
for (buf) |b, i| {
|
||||
const index = result_slice.len - i - 1 - padding;
|
||||
result_slice[index] = b;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Compares two slices and returns whether they are equal.
|
||||
pub fn eql(a: var, b: var) -> bool {
|
||||
pub fn eql(comptime T: type, a: []const T, b: []const T) -> bool {
|
||||
if (a.len != b.len) return false;
|
||||
for (a) |item, index| {
|
||||
if (b[index] != item) return false;
|
||||
@ -94,24 +77,96 @@ pub fn eql(a: var, b: var) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Reads an integer from memory with size equal to bytes.len.
|
||||
/// T specifies the return type, which must be large enough to store
|
||||
/// the result.
|
||||
pub fn readInt(bytes: []const u8, comptime T: type, big_endian: bool) -> T {
|
||||
var result: T = 0;
|
||||
if (big_endian) {
|
||||
for (bytes) |b| {
|
||||
result = (result << 8) | b;
|
||||
}
|
||||
} else {
|
||||
for (bytes) |b, index| {
|
||||
result = result | (T(b) << T(index * 8));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes
|
||||
/// to fill the entire buffer provided.
|
||||
/// value must be an integer.
|
||||
pub fn writeInt(buf: []u8, value: var, big_endian: bool) {
|
||||
const uint = @intType(false, @typeOf(value).bit_count);
|
||||
var bits = @truncate(uint, value);
|
||||
if (big_endian) {
|
||||
var index: usize = buf.len;
|
||||
while (index != 0) {
|
||||
index -= 1;
|
||||
|
||||
buf[index] = @truncate(u8, bits);
|
||||
bits >>= 8;
|
||||
}
|
||||
} else {
|
||||
for (buf) |*b| {
|
||||
*b = @truncate(u8, bits);
|
||||
bits >>= 8;
|
||||
}
|
||||
}
|
||||
assert(bits == 0);
|
||||
}
|
||||
|
||||
fn testStringEquality() {
|
||||
@setFnTest(this);
|
||||
|
||||
assert(eql("abcd", "abcd"));
|
||||
assert(!eql("abcdef", "abZdef"));
|
||||
assert(!eql("abcdefg", "abcdef"));
|
||||
assert(eql(u8, "abcd", "abcd"));
|
||||
assert(!eql(u8, "abcdef", "abZdef"));
|
||||
assert(!eql(u8, "abcdefg", "abcdef"));
|
||||
}
|
||||
|
||||
fn testSliceAsInt() {
|
||||
fn testReadInt() {
|
||||
@setFnTest(this);
|
||||
|
||||
testReadIntImpl();
|
||||
comptime testReadIntImpl();
|
||||
}
|
||||
fn testReadIntImpl() {
|
||||
{
|
||||
const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 };
|
||||
assert(readInt(bytes, u32, true) == 0x12345678);
|
||||
assert(readInt(bytes, u32, false) == 0x78563412);
|
||||
}
|
||||
{
|
||||
const buf = []u8{0x00, 0x00, 0x12, 0x34};
|
||||
const answer = sliceAsInt(buf[0...], true, u64);
|
||||
const answer = readInt(buf, u64, true);
|
||||
assert(answer == 0x00001234);
|
||||
}
|
||||
{
|
||||
const buf = []u8{0x12, 0x34, 0x00, 0x00};
|
||||
const answer = sliceAsInt(buf[0...], false, u64);
|
||||
const answer = readInt(buf, u64, false);
|
||||
assert(answer == 0x00003412);
|
||||
}
|
||||
}
|
||||
|
||||
fn testWriteInt() {
|
||||
@setFnTest(this);
|
||||
|
||||
testWriteIntImpl();
|
||||
comptime testWriteIntImpl();
|
||||
}
|
||||
fn testWriteIntImpl() {
|
||||
var bytes: [4]u8 = undefined;
|
||||
|
||||
writeInt(bytes[0...], u32(0x12345678), true);
|
||||
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
|
||||
|
||||
writeInt(bytes[0...], u32(0x78563412), false);
|
||||
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
|
||||
|
||||
writeInt(bytes[0...], u16(0x1234), true);
|
||||
assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 }));
|
||||
|
||||
writeInt(bytes[0...], u16(0x1234), false);
|
||||
assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 }));
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
|
||||
|
||||
pub fn connect(hostname: []const u8, port: u16) -> %Connection {
|
||||
var addrs_buf: [1]Address = undefined;
|
||||
const addrs_slice = %return lookup(hostname, addrs_buf);
|
||||
const addrs_slice = %return lookup(hostname, addrs_buf[0...]);
|
||||
const main_addr = &addrs_slice[0];
|
||||
|
||||
return connectAddr(main_addr, port);
|
||||
|
21
std/rand.zig
21
std/rand.zig
@ -1,5 +1,6 @@
|
||||
const assert = @import("debug.zig").assert;
|
||||
const rand_test = @import("rand_test.zig");
|
||||
const mem = @import("mem.zig");
|
||||
|
||||
pub const MT19937_32 = MersenneTwister(
|
||||
u32, 624, 397, 31,
|
||||
@ -28,14 +29,16 @@ pub const Rand = struct {
|
||||
r.rng.init(seed);
|
||||
}
|
||||
|
||||
/// Get an integer with random bits.
|
||||
/// Get an integer or boolean with random bits.
|
||||
pub fn scalar(r: &Rand, comptime T: type) -> T {
|
||||
if (T == usize) {
|
||||
return r.rng.get();
|
||||
} else if (T == bool) {
|
||||
return (r.rng.get() & 0b1) == 0;
|
||||
} else {
|
||||
var result: [@sizeOf(T)]u8 = undefined;
|
||||
r.fillBytes(result);
|
||||
return ([]T)(result)[0];
|
||||
r.fillBytes(result[0...]);
|
||||
return mem.readInt(result, T, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,12 +46,12 @@ pub const Rand = struct {
|
||||
pub fn fillBytes(r: &Rand, buf: []u8) {
|
||||
var bytes_left = buf.len;
|
||||
while (bytes_left >= @sizeOf(usize)) {
|
||||
([]usize)(buf[buf.len - bytes_left...])[0] = r.rng.get();
|
||||
mem.writeInt(buf[buf.len - bytes_left...], r.rng.get(), false);
|
||||
bytes_left -= @sizeOf(usize);
|
||||
}
|
||||
if (bytes_left > 0) {
|
||||
var rand_val_array : [@sizeOf(usize)]u8 = undefined;
|
||||
([]usize)(rand_val_array)[0] = r.rng.get();
|
||||
var rand_val_array: [@sizeOf(usize)]u8 = undefined;
|
||||
mem.writeInt(rand_val_array[0...], r.rng.get(), false);
|
||||
while (bytes_left > 0) {
|
||||
buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left];
|
||||
bytes_left -= 1;
|
||||
@ -63,11 +66,11 @@ pub const Rand = struct {
|
||||
const range = end - start;
|
||||
const leftover = @maxValue(T) % range;
|
||||
const upper_bound = @maxValue(T) - leftover;
|
||||
var rand_val_array : [@sizeOf(T)]u8 = undefined;
|
||||
var rand_val_array: [@sizeOf(T)]u8 = undefined;
|
||||
|
||||
while (true) {
|
||||
r.fillBytes(rand_val_array);
|
||||
const rand_val = ([]T)(rand_val_array)[0];
|
||||
r.fillBytes(rand_val_array[0...]);
|
||||
const rand_val = mem.readInt(rand_val_array, T, false);
|
||||
if (rand_val < upper_bound) {
|
||||
return start + (rand_val % range);
|
||||
}
|
||||
|
48
std/sort.zig
48
std/sort.zig
@ -61,13 +61,13 @@ fn reverse(was: Cmp) -> Cmp {
|
||||
fn testSort() {
|
||||
@setFnTest(this);
|
||||
|
||||
const u8cases = [][][]u8 {
|
||||
[][]u8{"", ""},
|
||||
[][]u8{"a", "a"},
|
||||
[][]u8{"az", "az"},
|
||||
[][]u8{"za", "az"},
|
||||
[][]u8{"asdf", "adfs"},
|
||||
[][]u8{"one", "eno"},
|
||||
const u8cases = [][]const []const u8 {
|
||||
[][]const u8{"", ""},
|
||||
[][]const u8{"a", "a"},
|
||||
[][]const u8{"az", "az"},
|
||||
[][]const u8{"za", "az"},
|
||||
[][]const u8{"asdf", "adfs"},
|
||||
[][]const u8{"one", "eno"},
|
||||
};
|
||||
|
||||
for (u8cases) |case| {
|
||||
@ -75,16 +75,16 @@ fn testSort() {
|
||||
const slice = buf[0...case[0].len];
|
||||
mem.copy(u8, slice, case[0]);
|
||||
sort(u8, slice, u8asc);
|
||||
assert(mem.eql(slice, case[1]));
|
||||
assert(mem.eql(u8, slice, case[1]));
|
||||
}
|
||||
|
||||
const i32cases = [][][]i32 {
|
||||
[][]i32{[]i32{}, []i32{}},
|
||||
[][]i32{[]i32{1}, []i32{1}},
|
||||
[][]i32{[]i32{0, 1}, []i32{0, 1}},
|
||||
[][]i32{[]i32{1, 0}, []i32{0, 1}},
|
||||
[][]i32{[]i32{1, -1, 0}, []i32{-1, 0, 1}},
|
||||
[][]i32{[]i32{2, 1, 3}, []i32{1, 2, 3}},
|
||||
const i32cases = [][]const []const i32 {
|
||||
[][]const i32{[]i32{}, []i32{}},
|
||||
[][]const i32{[]i32{1}, []i32{1}},
|
||||
[][]const i32{[]i32{0, 1}, []i32{0, 1}},
|
||||
[][]const i32{[]i32{1, 0}, []i32{0, 1}},
|
||||
[][]const i32{[]i32{1, -1, 0}, []i32{-1, 0, 1}},
|
||||
[][]const i32{[]i32{2, 1, 3}, []i32{1, 2, 3}},
|
||||
};
|
||||
|
||||
for (i32cases) |case| {
|
||||
@ -92,20 +92,20 @@ fn testSort() {
|
||||
const slice = buf[0...case[0].len];
|
||||
mem.copy(i32, slice, case[0]);
|
||||
sort(i32, slice, i32asc);
|
||||
assert(mem.eql(slice, case[1]));
|
||||
assert(mem.eql(i32, slice, case[1]));
|
||||
}
|
||||
}
|
||||
|
||||
fn testSortDesc() {
|
||||
@setFnTest(this);
|
||||
|
||||
const rev_cases = [][][]i32 {
|
||||
[][]i32{[]i32{}, []i32{}},
|
||||
[][]i32{[]i32{1}, []i32{1}},
|
||||
[][]i32{[]i32{0, 1}, []i32{1, 0}},
|
||||
[][]i32{[]i32{1, 0}, []i32{1, 0}},
|
||||
[][]i32{[]i32{1, -1, 0}, []i32{1, 0, -1}},
|
||||
[][]i32{[]i32{2, 1, 3}, []i32{3, 2, 1}},
|
||||
const rev_cases = [][]const []const i32 {
|
||||
[][]const i32{[]i32{}, []i32{}},
|
||||
[][]const i32{[]i32{1}, []i32{1}},
|
||||
[][]const i32{[]i32{0, 1}, []i32{1, 0}},
|
||||
[][]const i32{[]i32{1, 0}, []i32{1, 0}},
|
||||
[][]const i32{[]i32{1, -1, 0}, []i32{1, 0, -1}},
|
||||
[][]const i32{[]i32{2, 1, 3}, []i32{3, 2, 1}},
|
||||
};
|
||||
|
||||
for (rev_cases) |case| {
|
||||
@ -113,6 +113,6 @@ fn testSortDesc() {
|
||||
const slice = buf[0...case[0].len];
|
||||
mem.copy(i32, slice, case[0]);
|
||||
sort(i32, slice, i32desc);
|
||||
assert(mem.eql(slice, case[1]));
|
||||
assert(mem.eql(i32, slice, case[1]));
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ fn arrays() {
|
||||
assert(accumulator == 15);
|
||||
assert(getArrayLen(array) == 5);
|
||||
}
|
||||
fn getArrayLen(a: []u32) -> usize {
|
||||
fn getArrayLen(a: []const u32) -> usize {
|
||||
a.len
|
||||
}
|
||||
|
||||
@ -61,12 +61,12 @@ const some_array = []u8 {0, 1, 2, 3};
|
||||
fn nestedArrays() {
|
||||
@setFnTest(this);
|
||||
|
||||
const array_of_strings = [][]u8 {"hello", "this", "is", "my", "thing"};
|
||||
const array_of_strings = [][]const u8 {"hello", "this", "is", "my", "thing"};
|
||||
for (array_of_strings) |s, i| {
|
||||
if (i == 0) assert(mem.eql(s, "hello"));
|
||||
if (i == 1) assert(mem.eql(s, "this"));
|
||||
if (i == 2) assert(mem.eql(s, "is"));
|
||||
if (i == 3) assert(mem.eql(s, "my"));
|
||||
if (i == 4) assert(mem.eql(s, "thing"));
|
||||
if (i == 0) assert(mem.eql(u8, s, "hello"));
|
||||
if (i == 1) assert(mem.eql(u8, s, "this"));
|
||||
if (i == 2) assert(mem.eql(u8, s, "is"));
|
||||
if (i == 3) assert(mem.eql(u8, s, "my"));
|
||||
if (i == 4) assert(mem.eql(u8, s, "thing"));
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ fn enumWithMembers() {
|
||||
const b = ET.UINT { 42 };
|
||||
var buf: [20]u8 = undefined;
|
||||
|
||||
assert(%%a.print(buf) == 3);
|
||||
assert(mem.eql(buf[0...3], "-42"));
|
||||
assert(%%a.print(buf[0...]) == 3);
|
||||
assert(mem.eql(u8, buf[0...3], "-42"));
|
||||
|
||||
assert(%%b.print(buf) == 2);
|
||||
assert(mem.eql(buf[0...2], "42"));
|
||||
assert(%%b.print(buf[0...]) == 2);
|
||||
assert(mem.eql(u8, buf[0...2], "42"));
|
||||
}
|
||||
|
@ -28,8 +28,8 @@ fn gimmeItBroke() -> []const u8 {
|
||||
|
||||
fn errorName() {
|
||||
@setFnTest(this);
|
||||
assert(mem.eql(@errorName(error.AnError), "AnError"));
|
||||
assert(mem.eql(@errorName(error.ALongerErrorName), "ALongerErrorName"));
|
||||
assert(mem.eql(u8, @errorName(error.AnError), "AnError"));
|
||||
assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
|
||||
}
|
||||
error AnError;
|
||||
error ALongerErrorName;
|
||||
|
@ -283,3 +283,21 @@ fn callMethodOnBoundFnReferringToVarInstance() {
|
||||
|
||||
assert(bound_fn() == 1237);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn ptrToLocalArrayArgumentAtComptime() {
|
||||
@setFnTest(this);
|
||||
|
||||
comptime {
|
||||
var bytes: [10]u8 = undefined;
|
||||
modifySomeBytes(bytes[0...]);
|
||||
assert(bytes[0] == 'a');
|
||||
assert(bytes[9] == 'b');
|
||||
}
|
||||
}
|
||||
|
||||
fn modifySomeBytes(bytes: []u8) {
|
||||
bytes[0] = 'a';
|
||||
bytes[9] = 'b';
|
||||
}
|
||||
|
@ -22,12 +22,42 @@ fn forLoopWithPointerElemVar() {
|
||||
|
||||
const source = "abcdefg";
|
||||
var target: [source.len]u8 = undefined;
|
||||
@memcpy(&target[0], &source[0], source.len);
|
||||
mangleString(target);
|
||||
assert(mem.eql(target, "bcdefgh"));
|
||||
mem.copy(u8, target[0...], source);
|
||||
mangleString(target[0...]);
|
||||
assert(mem.eql(u8, target, "bcdefgh"));
|
||||
}
|
||||
fn mangleString(s: []u8) {
|
||||
for (s) |*c| {
|
||||
*c += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn basicForLoop() {
|
||||
@setFnTest(this);
|
||||
|
||||
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 buf_index: usize = 0;
|
||||
|
||||
const array = []u8 {9, 8, 7, 6};
|
||||
for (array) |item| {
|
||||
buffer[buf_index] = item;
|
||||
buf_index += 1;
|
||||
}
|
||||
for (array) |item, index| {
|
||||
buffer[buf_index] = u8(index);
|
||||
buf_index += 1;
|
||||
}
|
||||
const unknown_size: []const u8 = array;
|
||||
for (unknown_size) |item| {
|
||||
buffer[buf_index] = item;
|
||||
buf_index += 1;
|
||||
}
|
||||
for (unknown_size) |item, index| {
|
||||
buffer[buf_index] = u8(index);
|
||||
buf_index += 1;
|
||||
}
|
||||
|
||||
assert(mem.eql(u8, buffer[0...buf_index], expected_result));
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ fn genericFnWithImplicitCast() {
|
||||
assert(getFirstByte(u8, []u8 {13}) == 13);
|
||||
assert(getFirstByte(u16, []u16 {0, 13}) == 0);
|
||||
}
|
||||
fn getByte(ptr: ?&u8) -> u8 {*??ptr}
|
||||
fn getFirstByte(comptime T: type, mem: []T) -> u8 {
|
||||
getByte((&u8)(&mem[0]))
|
||||
fn getByte(ptr: ?&const u8) -> u8 {*??ptr}
|
||||
fn getFirstByte(comptime T: type, mem: []const T) -> u8 {
|
||||
getByte((&const u8)(&mem[0]))
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ fn first4KeysOfHomeRow() -> []const u8 {
|
||||
fn ReturnStringFromFunction() {
|
||||
@setFnTest(this);
|
||||
|
||||
assert(mem.eql(first4KeysOfHomeRow(), "aoeu"));
|
||||
assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
|
||||
}
|
||||
|
||||
const g1 : i32 = 1233 + 1;
|
||||
@ -210,31 +210,31 @@ fn emptyFn() {}
|
||||
fn hexEscape() {
|
||||
@setFnTest(this);
|
||||
|
||||
assert(mem.eql("\x68\x65\x6c\x6c\x6f", "hello"));
|
||||
assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
|
||||
}
|
||||
|
||||
fn stringConcatenation() {
|
||||
@setFnTest(this);
|
||||
|
||||
assert(mem.eql("OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
|
||||
assert(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
|
||||
}
|
||||
|
||||
fn arrayMultOperator() {
|
||||
@setFnTest(this);
|
||||
|
||||
assert(mem.eql("ab" ** 5, "ababababab"));
|
||||
assert(mem.eql(u8, "ab" ** 5, "ababababab"));
|
||||
}
|
||||
|
||||
fn stringEscapes() {
|
||||
@setFnTest(this);
|
||||
|
||||
assert(mem.eql("\"", "\x22"));
|
||||
assert(mem.eql("\'", "\x27"));
|
||||
assert(mem.eql("\n", "\x0a"));
|
||||
assert(mem.eql("\r", "\x0d"));
|
||||
assert(mem.eql("\t", "\x09"));
|
||||
assert(mem.eql("\\", "\x5c"));
|
||||
assert(mem.eql("\u1234\u0069", "\xe1\x88\xb4\x69"));
|
||||
assert(mem.eql(u8, "\"", "\x22"));
|
||||
assert(mem.eql(u8, "\'", "\x27"));
|
||||
assert(mem.eql(u8, "\n", "\x0a"));
|
||||
assert(mem.eql(u8, "\r", "\x0d"));
|
||||
assert(mem.eql(u8, "\t", "\x09"));
|
||||
assert(mem.eql(u8, "\\", "\x5c"));
|
||||
assert(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69"));
|
||||
}
|
||||
|
||||
fn multilineString() {
|
||||
@ -246,7 +246,7 @@ fn multilineString() {
|
||||
\\three
|
||||
;
|
||||
const s2 = "one\ntwo)\nthree";
|
||||
assert(mem.eql(s1, s2));
|
||||
assert(mem.eql(u8, s1, s2));
|
||||
}
|
||||
|
||||
fn multilineCString() {
|
||||
@ -302,7 +302,7 @@ fn castUndefined() {
|
||||
@setFnTest(this);
|
||||
|
||||
const array: [100]u8 = undefined;
|
||||
const slice = ([]u8)(array);
|
||||
const slice = ([]const u8)(array);
|
||||
testCastUndefined(slice);
|
||||
}
|
||||
fn testCastUndefined(x: []const u8) {}
|
||||
@ -344,14 +344,14 @@ fn pointerDereferencing() {
|
||||
fn callResultOfIfElseExpression() {
|
||||
@setFnTest(this);
|
||||
|
||||
assert(mem.eql(f2(true), "a"));
|
||||
assert(mem.eql(f2(false), "b"));
|
||||
assert(mem.eql(u8, f2(true), "a"));
|
||||
assert(mem.eql(u8, f2(false), "b"));
|
||||
}
|
||||
fn f2(x: bool) -> []u8 {
|
||||
fn f2(x: bool) -> []const u8 {
|
||||
return (if (x) fA else fB)();
|
||||
}
|
||||
fn fA() -> []u8 { "a" }
|
||||
fn fB() -> []u8 { "b" }
|
||||
fn fA() -> []const u8 { "a" }
|
||||
fn fB() -> []const u8 { "b" }
|
||||
|
||||
|
||||
fn constExpressionEvalHandlingOfVariables() {
|
||||
@ -434,7 +434,7 @@ fn intToPtrCast() {
|
||||
fn pointerComparison() {
|
||||
@setFnTest(this);
|
||||
|
||||
const a = ([]u8)("a");
|
||||
const a = ([]const u8)("a");
|
||||
const b = &a;
|
||||
assert(ptrEql(b, b));
|
||||
}
|
||||
@ -463,7 +463,7 @@ fn castSliceToU8Slice() {
|
||||
|
||||
assert(@sizeOf(i32) == 4);
|
||||
var big_thing_array = []i32{1, 2, 3, 4};
|
||||
const big_thing_slice: []i32 = big_thing_array;
|
||||
const big_thing_slice: []i32 = big_thing_array[0...];
|
||||
const bytes = ([]u8)(big_thing_slice);
|
||||
assert(bytes.len == 4 * 4);
|
||||
bytes[4] = 0;
|
||||
@ -562,8 +562,8 @@ fn typeName() {
|
||||
@setFnTest(this);
|
||||
|
||||
comptime {
|
||||
assert(mem.eql(@typeName(i64), "i64"));
|
||||
assert(mem.eql(@typeName(&usize), "&usize"));
|
||||
assert(mem.eql(u8, @typeName(i64), "i64"));
|
||||
assert(mem.eql(u8, @typeName(&usize), "&usize"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ fn passSliceOfEmptyStructToFn() {
|
||||
|
||||
assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1);
|
||||
}
|
||||
fn testPassSliceOfEmptyStructToFn(slice: []EmptyStruct2) -> usize {
|
||||
fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) -> usize {
|
||||
slice.len
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ fn structContainsSliceOfItself() {
|
||||
},
|
||||
Node {
|
||||
.payload = 3,
|
||||
.children = []Node{
|
||||
.children = ([]Node{
|
||||
Node {
|
||||
.payload = 31,
|
||||
.children = []Node{},
|
||||
@ -28,7 +28,7 @@ fn structContainsSliceOfItself() {
|
||||
.payload = 32,
|
||||
.children = []Node{},
|
||||
},
|
||||
},
|
||||
})[0...],
|
||||
},
|
||||
};
|
||||
const root = Node {
|
||||
|
@ -465,27 +465,6 @@ fn print_ok(val: @typeOf(x)) -> @typeOf(foo) {
|
||||
const foo : i32 = 0;
|
||||
)SOURCE", "OK\n");
|
||||
|
||||
add_simple_case("for loops", R"SOURCE(
|
||||
const io = @import("std").io;
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
const array = []u8 {9, 8, 7, 6};
|
||||
for (array) |item| {
|
||||
%%io.stdout.printf("{}\n", item);
|
||||
}
|
||||
for (array) |item, index| {
|
||||
%%io.stdout.printf("{}\n", index);
|
||||
}
|
||||
const unknown_size: []u8 = array;
|
||||
for (unknown_size) |item| {
|
||||
%%io.stdout.printf("{}\n", item);
|
||||
}
|
||||
for (unknown_size) |item, index| {
|
||||
%%io.stdout.printf("{}\n", index);
|
||||
}
|
||||
}
|
||||
)SOURCE", "9\n8\n7\n6\n0\n1\n2\n3\n9\n8\n7\n6\n0\n1\n2\n3\n");
|
||||
|
||||
add_simple_case_libc("expose function pointer to C land", R"SOURCE(
|
||||
const c = @cImport(@cInclude("stdlib.h"));
|
||||
|
||||
@ -1350,13 +1329,6 @@ fn f() -> i8 {
|
||||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:4:19: error: expected signed integer type, found 'u32'");
|
||||
|
||||
add_compile_fail_case("truncate same bit count", R"SOURCE(
|
||||
fn f() -> i8 {
|
||||
const x: i8 = 10;
|
||||
@truncate(i8, x)
|
||||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:4:19: error: type 'i8' has same or fewer bits than destination type 'i8'");
|
||||
|
||||
add_compile_fail_case("%return in function with non error return type", R"SOURCE(
|
||||
fn f() {
|
||||
%return something();
|
||||
@ -1396,9 +1368,9 @@ fn f() -> i32 {
|
||||
add_compile_fail_case("convert fixed size array to slice with invalid size", R"SOURCE(
|
||||
fn f() {
|
||||
var array: [5]u8 = undefined;
|
||||
var foo = ([]u32)(array)[0];
|
||||
var foo = ([]const u32)(array)[0];
|
||||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:4:22: error: unable to convert [5]u8 to []u32: size mismatch");
|
||||
)SOURCE", 1, ".tmp_source.zig:4:28: error: unable to convert [5]u8 to []const u32: size mismatch");
|
||||
|
||||
add_compile_fail_case("non-pure function returns type", R"SOURCE(
|
||||
var a: u32 = 0;
|
||||
@ -1664,7 +1636,7 @@ pub fn main(args: [][]u8) -> %void {
|
||||
const a = []i32{1, 2, 3, 4};
|
||||
baz(bar(a));
|
||||
}
|
||||
fn bar(a: []i32) -> i32 {
|
||||
fn bar(a: []const i32) -> i32 {
|
||||
a[4]
|
||||
}
|
||||
fn baz(a: i32) { }
|
||||
@ -1799,8 +1771,8 @@ pub fn main(args: [][]u8) -> %void {
|
||||
const x = widenSlice([]u8{1, 2, 3, 4, 5});
|
||||
if (x.len == 0) return error.Whatever;
|
||||
}
|
||||
fn widenSlice(slice: []u8) -> []i32 {
|
||||
([]i32)(slice)
|
||||
fn widenSlice(slice: []const u8) -> []const i32 {
|
||||
([]const i32)(slice)
|
||||
}
|
||||
)SOURCE");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user