Merge pull request #125 from birth-software/sliceable-structs
Introduce sliceable structs
This commit is contained in:
commit
df17a5f89b
@ -42,6 +42,13 @@ const Error = struct {
|
||||
node: Node.Index,
|
||||
};
|
||||
|
||||
const SliceField = enum {
|
||||
pointer,
|
||||
length,
|
||||
};
|
||||
|
||||
const length_field_name = @tagName(SliceField.length);
|
||||
|
||||
pub fn createContext(allocator: Allocator, my_allocator: *MyAllocator) !*const Context {
|
||||
const context: *Context = try allocator.create(Context);
|
||||
|
||||
@ -3576,10 +3583,11 @@ pub const Instruction = union(enum) {
|
||||
};
|
||||
|
||||
pub const GEP = struct {
|
||||
index: V,
|
||||
pointer: Instruction.Index,
|
||||
base_type: Type.Index,
|
||||
name: u32,
|
||||
is_struct: bool,
|
||||
index: V,
|
||||
};
|
||||
|
||||
const ExtractValue = struct {
|
||||
@ -3815,27 +3823,6 @@ pub const Function = struct {
|
||||
expand,
|
||||
};
|
||||
|
||||
// const AbiType = union(enum) {
|
||||
// type: Type.Index,
|
||||
// integer_bit_count: u32,
|
||||
// invalid,
|
||||
//
|
||||
// fn is_promotable_integer_or_bool(abi_type: AbiType, unit: *Unit) bool {
|
||||
// switch (abi_type) {
|
||||
// .type => |type_index| if (get_integer_or_bool(type_index, unit)) |integer| {
|
||||
// return integer.bit_count < 32;
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn get_integer_or_bool(type_index: Type.Index, unit: *Unit) ?Type.Integer {
|
||||
// return switch (unit.types.get(type_index).*) {
|
||||
// .integer => true,
|
||||
// else => false,
|
||||
// };
|
||||
// }
|
||||
// };
|
||||
|
||||
const AbiAttributes = struct {
|
||||
by_reg: bool = false,
|
||||
zero_extend: bool = false,
|
||||
@ -3873,6 +3860,18 @@ pub const Struct = struct {
|
||||
pub const Descriptor = struct {
|
||||
scope: Debug.Scope.Global,
|
||||
fields: UnpinnedArray(Struct.Field.Index) = .{},
|
||||
options: Options,
|
||||
};
|
||||
pub const Options = struct {
|
||||
sliceable: ?Sliceable = null,
|
||||
pub const Id = enum {
|
||||
sliceable,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Sliceable = struct {
|
||||
pointer: u32,
|
||||
length: u32,
|
||||
};
|
||||
|
||||
pub const Field = struct {
|
||||
@ -4861,7 +4860,7 @@ pub const Builder = struct {
|
||||
_ = try builder.analyzeFile(unit, context, file_index);
|
||||
}
|
||||
|
||||
fn analyzeFile(builder: *Builder, unit: *Unit, context: *const Context, file_index: Debug.File.Index) !void {
|
||||
fn analyzeFile(builder: *Builder, unit: *Unit, context: *const Context, file_index: Debug.File.Index) anyerror!void {
|
||||
const old_function = builder.current_function;
|
||||
builder.current_function = .null;
|
||||
defer builder.current_function = old_function;
|
||||
@ -5188,7 +5187,7 @@ pub const Builder = struct {
|
||||
assert(declaration.kind == .argument);
|
||||
assert(scope.kind == .function);
|
||||
|
||||
const argument_declaration: *Debug.Declaration.Argument =@fieldParentPtr("declaration", declaration);
|
||||
const argument_declaration: *Debug.Declaration.Argument = @fieldParentPtr("declaration", declaration);
|
||||
const function_scope: *Debug.Scope.Function = @fieldParentPtr("scope", scope);
|
||||
const instruction_index = function_scope.argument_map.get(argument_declaration).?;
|
||||
|
||||
@ -6163,12 +6162,7 @@ pub const Builder = struct {
|
||||
} else {
|
||||
const left = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, node.left, .left);
|
||||
const expected_right_type = switch (left.value) {
|
||||
.runtime => |instr_index| switch (unit.instructions.get(instr_index).*) {
|
||||
// .global => |global| global.declaration.type,
|
||||
.stack_slot => |stack_slot| stack_slot.type,
|
||||
.get_element_pointer => |gep| gep.base_type,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.runtime => unit.types.get(left.type).pointer.type,
|
||||
.@"comptime" => |ct| switch (ct) {
|
||||
.global => |global| global.declaration.type,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
@ -6524,6 +6518,35 @@ pub const Builder = struct {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_builtin_declaration(builder: *Builder, unit: *Unit, context: *const Context, name: []const u8) !*Debug.Declaration.Global {
|
||||
const std_file_index = try builder.resolveImportStringLiteral(unit, context, Type.Expect{ .type = .type }, "std");
|
||||
const std_file = unit.files.get(std_file_index);
|
||||
const std_file_struct_index = unit.types.get(std_file.type).@"struct";
|
||||
const std_file_struct = unit.structs.get(std_file_struct_index);
|
||||
const builtin_hash = try unit.processIdentifier(context, "builtin");
|
||||
|
||||
const look_in_parent_scopes = false;
|
||||
if (std_file_struct.kind.@"struct".scope.scope.lookupDeclaration(builtin_hash, look_in_parent_scopes)) |lookup| {
|
||||
const builtin_declaration = try builder.referenceGlobalDeclaration(unit, context, &std_file_struct.kind.@"struct".scope.scope, lookup.declaration, .{});
|
||||
switch (builtin_declaration.initial_value) {
|
||||
.type => |builtin_type_index| {
|
||||
const builtin_type_struct_index = unit.types.get(builtin_type_index).@"struct";
|
||||
const builtin_type_struct = &unit.structs.get(builtin_type_struct_index).kind.@"struct";
|
||||
const hash = try unit.processIdentifier(context, name);
|
||||
if (builtin_type_struct.scope.scope.lookupDeclaration(hash, look_in_parent_scopes)) |declaration_lookup| {
|
||||
const declaration_global = try builder.referenceGlobalDeclaration(unit, context, declaration_lookup.scope, declaration_lookup.declaration, .{});
|
||||
return declaration_global;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
} else {
|
||||
@panic("Internal compiler error");
|
||||
}
|
||||
}
|
||||
|
||||
fn resolveFunctionPrototype(builder: *Builder, unit: *Unit, context: *const Context, node_index: Node.Index, global_attributes: Debug.Declaration.Global.Attributes) !Type.Index {
|
||||
const node = unit.getNode(node_index);
|
||||
assert(node.id == .function_prototype);
|
||||
@ -6544,32 +6567,8 @@ pub const Builder = struct {
|
||||
.function_attribute_naked => is_naked = true,
|
||||
.function_attribute_cc => {
|
||||
if (unit.cc_type == .null) {
|
||||
const std_file_index = try builder.resolveImportStringLiteral(unit, context, Type.Expect{ .type = .type }, "std");
|
||||
const std_file = unit.files.get(std_file_index);
|
||||
const std_file_struct_index = unit.types.get(std_file.type).@"struct";
|
||||
const std_file_struct = unit.structs.get(std_file_struct_index);
|
||||
const builtin_hash = try unit.processIdentifier(context, "builtin");
|
||||
|
||||
const look_in_parent_scopes = false;
|
||||
if (std_file_struct.kind.@"struct".scope.scope.lookupDeclaration(builtin_hash, look_in_parent_scopes)) |lookup| {
|
||||
const builtin_declaration = try builder.referenceGlobalDeclaration(unit, context, &std_file_struct.kind.@"struct".scope.scope, lookup.declaration, .{});
|
||||
switch (builtin_declaration.initial_value) {
|
||||
.type => |builtin_type_index| {
|
||||
const builtin_type_struct_index = unit.types.get(builtin_type_index).@"struct";
|
||||
const builtin_type_struct = &unit.structs.get(builtin_type_struct_index).kind.@"struct";
|
||||
const cc_hash = try unit.processIdentifier(context, "CallingConvention");
|
||||
if (builtin_type_struct.scope.scope.lookupDeclaration(cc_hash, look_in_parent_scopes)) |cc_lookup| {
|
||||
const cc_global = try builder.referenceGlobalDeclaration(unit, context, cc_lookup.scope, cc_lookup.declaration, .{});
|
||||
unit.cc_type = cc_global.initial_value.type;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
} else {
|
||||
@panic("Internal compiler error");
|
||||
}
|
||||
const calling_convention_declaration = try builder.get_builtin_declaration(unit, context, "CallingConvention");
|
||||
unit.cc_type = calling_convention_declaration.initial_value.type;
|
||||
}
|
||||
|
||||
assert(unit.cc_type != .null);
|
||||
@ -7502,6 +7501,48 @@ pub const Builder = struct {
|
||||
const data: Data = switch (container_type) {
|
||||
.@"struct" => b: {
|
||||
assert(container_node.id == .struct_type);
|
||||
|
||||
var struct_options = Struct.Options{};
|
||||
|
||||
if (container_node.right != .null) {
|
||||
const struct_option_nodes = unit.getNodeList(container_node.right);
|
||||
var struct_options_value = false;
|
||||
for (struct_option_nodes) |struct_option_node_index| {
|
||||
const struct_option_node = unit.getNode(struct_option_node_index);
|
||||
switch (struct_option_node.id) {
|
||||
.anonymous_container_literal => {
|
||||
if (struct_options_value) unreachable;
|
||||
struct_options_value = true;
|
||||
assert(struct_option_node.left == .null);
|
||||
const nodes = unit.getNodeList(struct_option_node.right);
|
||||
const struct_options_declaration = try builder.get_builtin_declaration(unit, context, "StructOptions");
|
||||
const struct_options_declaration_type_index = struct_options_declaration.initial_value.type;
|
||||
const struct_options_literal = try builder.resolveContainerLiteral(unit, context, nodes, struct_options_declaration_type_index);
|
||||
const constant_struct_index = struct_options_literal.value.@"comptime".constant_struct;
|
||||
const constant_struct = unit.constant_structs.get(constant_struct_index);
|
||||
const struct_options_struct_index = unit.types.get(struct_options_declaration_type_index).@"struct";
|
||||
const struct_options_struct = unit.structs.get(struct_options_struct_index);
|
||||
|
||||
for (struct_options_struct.kind.@"struct".fields.slice(), constant_struct.fields) |field_index, field_value| {
|
||||
const field = unit.struct_fields.get(field_index);
|
||||
const name = unit.getIdentifier(field.name);
|
||||
const option_id = data_structures.enumFromString(Struct.Options.Id, name) orelse unreachable;
|
||||
switch (option_id) {
|
||||
.sliceable => switch (field_value.bool) {
|
||||
true => struct_options.sliceable = .{
|
||||
.pointer = 0,
|
||||
.length = 1,
|
||||
},
|
||||
false => unreachable,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const struct_index = try unit.structs.append(context.my_allocator, .{
|
||||
.kind = .{
|
||||
.@"struct" = .{
|
||||
@ -7518,6 +7559,7 @@ pub const Builder = struct {
|
||||
.file = builder.current_file,
|
||||
},
|
||||
},
|
||||
.options = struct_options,
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -7530,7 +7572,7 @@ pub const Builder = struct {
|
||||
// Save file type
|
||||
switch (builder.current_scope.kind) {
|
||||
.file => {
|
||||
const global_scope: *Debug.Scope.Global= @fieldParentPtr("scope", builder.current_scope);
|
||||
const global_scope: *Debug.Scope.Global = @fieldParentPtr("scope", builder.current_scope);
|
||||
const file: *Debug.File = @fieldParentPtr("scope", global_scope);
|
||||
file.type = type_index;
|
||||
try unit.scope_container_map.put_no_clobber(context.my_allocator, &struct_type.kind.@"struct".scope.scope, type_index);
|
||||
@ -7555,7 +7597,9 @@ pub const Builder = struct {
|
||||
.kind = .comptime_int,
|
||||
},
|
||||
else => e: {
|
||||
const backing_type_index = try builder.resolveType(unit, context, container_node.right);
|
||||
const node_list = unit.getNodeList(container_node.right);
|
||||
assert(node_list.len == 1);
|
||||
const backing_type_index = try builder.resolveType(unit, context, node_list[0]);
|
||||
const backing_type = unit.types.get(backing_type_index);
|
||||
break :e switch (backing_type.*) {
|
||||
.integer => |integer| switch (integer.kind) {
|
||||
@ -7598,7 +7642,9 @@ pub const Builder = struct {
|
||||
const integer = switch (container_node.right) {
|
||||
.null => unreachable,
|
||||
else => e: {
|
||||
const backing_type_index = try builder.resolveType(unit, context, container_node.right);
|
||||
const argument_nodes = unit.getNodeList(container_node.right);
|
||||
assert(argument_nodes.len == 1);
|
||||
const backing_type_index = try builder.resolveType(unit, context, argument_nodes[0]);
|
||||
const backing_type = unit.types.get(backing_type_index);
|
||||
break :e switch (backing_type.*) {
|
||||
.integer => |integer| switch (integer.kind) {
|
||||
@ -7811,6 +7857,9 @@ pub const Builder = struct {
|
||||
},
|
||||
}
|
||||
|
||||
var sliceable_pointer_index: ?u32 = null;
|
||||
var sliceable_length_index: ?u32 = null;
|
||||
|
||||
for (field_nodes.slice(), 0..) |field_node_index, index| {
|
||||
const field_node = unit.getNode(field_node_index);
|
||||
const identifier = unit.getExpectedTokenBytes(field_node.token, .identifier);
|
||||
@ -7847,8 +7896,23 @@ pub const Builder = struct {
|
||||
.@"struct" => {
|
||||
assert(field_node.id == .container_field);
|
||||
const struct_type = unit.structs.get(ty.@"struct");
|
||||
const field_name = unit.getExpectedTokenBytes(field_node.token, .identifier);
|
||||
const field_name_hash = try unit.processIdentifier(context, field_name);
|
||||
if (struct_type.kind.@"struct".options.sliceable != null) {
|
||||
inline for (@typeInfo(SliceField).Enum.fields) |field| {
|
||||
if (byte_equal(field.name, identifier)) {
|
||||
const v = @field(SliceField, field.name);
|
||||
switch (v) {
|
||||
.pointer => {
|
||||
assert(sliceable_pointer_index == null);
|
||||
sliceable_pointer_index = @intCast(index);
|
||||
},
|
||||
.length => {
|
||||
assert(sliceable_length_index == null);
|
||||
sliceable_length_index = @intCast(index);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const field_type = try builder.resolveType(unit, context, field_node.left);
|
||||
const field_default_value: ?V.Comptime = switch (field_node.right) {
|
||||
.null => null,
|
||||
@ -7856,7 +7920,7 @@ pub const Builder = struct {
|
||||
};
|
||||
|
||||
const struct_field = try unit.struct_fields.append(context.my_allocator, .{
|
||||
.name = field_name_hash,
|
||||
.name = hash,
|
||||
.type = field_type,
|
||||
.default_value = field_default_value,
|
||||
});
|
||||
@ -7882,6 +7946,17 @@ pub const Builder = struct {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
switch (container_type) {
|
||||
.@"struct" => {
|
||||
const struct_type = unit.structs.get(ty.@"struct");
|
||||
if (struct_type.kind.@"struct".options.sliceable) |*sliceable| {
|
||||
sliceable.pointer = sliceable_pointer_index orelse unreachable;
|
||||
sliceable.length = sliceable_length_index orelse unreachable;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
if (count.comptime_blocks > 0) {
|
||||
@ -8278,10 +8353,6 @@ pub const Builder = struct {
|
||||
});
|
||||
try builder.appendInstruction(unit, context, first_store);
|
||||
|
||||
// TODO: should we use this?
|
||||
// const offset = @divExact(high_offset, high_aligned_size);
|
||||
// _ = offset; // autofix
|
||||
|
||||
const gep = try unit.instructions.append(context.my_allocator, .{
|
||||
.get_element_pointer = .{
|
||||
.pointer = stack,
|
||||
@ -8297,6 +8368,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .usize,
|
||||
},
|
||||
.name = try unit.processIdentifier(context, "direct_pair"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -9498,6 +9570,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = try unit.processIdentifier(context, "slice_end_gep"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -9614,6 +9687,7 @@ pub const Builder = struct {
|
||||
.is_struct = false,
|
||||
.base_type = slice.child_type,
|
||||
.index = range_start,
|
||||
.name = try unit.processIdentifier(context, "slice_pointer_gep"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, pointer_gep);
|
||||
@ -9667,6 +9741,7 @@ pub const Builder = struct {
|
||||
.is_struct = false,
|
||||
.base_type = pointer.type,
|
||||
.index = range_start,
|
||||
.name = try unit.processIdentifier(context, "pointer_many_slice"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, pointer_gep);
|
||||
@ -9736,6 +9811,7 @@ pub const Builder = struct {
|
||||
.base_type = array.type,
|
||||
.is_struct = false,
|
||||
.index = range_start,
|
||||
.name = try unit.processIdentifier(context, "array_slice"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, pointer_gep);
|
||||
@ -9813,6 +9889,7 @@ pub const Builder = struct {
|
||||
.base_type = child_pointer.type,
|
||||
.is_struct = false,
|
||||
.index = range_start,
|
||||
.name = try unit.processIdentifier(context, "double_many_pointer_slice"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, pointer_gep);
|
||||
@ -9889,6 +9966,7 @@ pub const Builder = struct {
|
||||
.base_type = array.type,
|
||||
.is_struct = false,
|
||||
.index = range_start,
|
||||
.name = try unit.processIdentifier(context, "double_array_slice"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, pointer_gep);
|
||||
@ -9980,6 +10058,7 @@ pub const Builder = struct {
|
||||
.base_type = slice.child_type,
|
||||
.is_struct = false,
|
||||
.index = range_start,
|
||||
.name = try unit.processIdentifier(context, "slice_ptr_gep"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, pointer_gep);
|
||||
@ -10495,76 +10574,26 @@ pub const Builder = struct {
|
||||
assert(node.right != .null);
|
||||
|
||||
const array_like_expression = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, node.left, .left);
|
||||
const index = try builder.resolveRuntimeValue(unit, context, Type.Expect{ .type = .usize }, node.right, .right);
|
||||
const original_index_value = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, node.right, .right);
|
||||
const index = switch (original_index_value.type) {
|
||||
.comptime_int => V{
|
||||
.value = .{
|
||||
.@"comptime" = .{
|
||||
.constant_int = .{
|
||||
.value = original_index_value.value.@"comptime".comptime_int.value,
|
||||
},
|
||||
},
|
||||
},
|
||||
.type = .usize,
|
||||
},
|
||||
else => original_index_value,
|
||||
};
|
||||
|
||||
const gep: V = switch (unit.types.get(array_like_expression.type).*) {
|
||||
.pointer => |pointer| switch (pointer.many) {
|
||||
true => unreachable,
|
||||
false => switch (unit.types.get(pointer.type).*) {
|
||||
.slice => |slice| b: {
|
||||
const gep = try unit.instructions.append(context.my_allocator, .{
|
||||
.get_element_pointer = .{
|
||||
.pointer = array_like_expression.value.runtime,
|
||||
.base_type = pointer.type,
|
||||
.is_struct = true,
|
||||
.index = .{
|
||||
.value = .{
|
||||
.@"comptime" = .{
|
||||
.constant_int = .{
|
||||
.value = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
|
||||
const pointer_to_slice_pointer = try unit.getPointerType(context, .{
|
||||
.type = slice.child_pointer_type,
|
||||
.mutability = pointer.mutability,
|
||||
.termination = .none,
|
||||
.many = false,
|
||||
.nullable = false,
|
||||
});
|
||||
|
||||
const pointer_load = try unit.instructions.append(context.my_allocator, .{
|
||||
.load = .{
|
||||
.value = .{
|
||||
.value = .{
|
||||
.runtime = gep,
|
||||
},
|
||||
.type = pointer_to_slice_pointer,
|
||||
},
|
||||
.type = slice.child_pointer_type,
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, pointer_load);
|
||||
|
||||
const slice_pointer_gep = try unit.instructions.append(context.my_allocator, .{
|
||||
.get_element_pointer = .{
|
||||
.pointer = pointer_load,
|
||||
.base_type = slice.child_type,
|
||||
.is_struct = false,
|
||||
.index = index,
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, slice_pointer_gep);
|
||||
|
||||
break :b .{
|
||||
.value = .{
|
||||
.runtime = slice_pointer_gep,
|
||||
},
|
||||
.type = try unit.getPointerType(context, .{
|
||||
.type = slice.child_type,
|
||||
.mutability = slice.mutability,
|
||||
.many = false,
|
||||
.nullable = false,
|
||||
.termination = .none,
|
||||
}),
|
||||
};
|
||||
},
|
||||
.slice => |slice| try builder.build_slice_indexed_access(unit, context, array_like_expression, pointer.type, slice.child_pointer_type, slice.child_type, slice.mutability, .{ .pointer = 0, .length = 1 }, index),
|
||||
.array => |array| b: {
|
||||
const gep = try unit.instructions.append(context.my_allocator, .{
|
||||
.get_element_pointer = .{
|
||||
@ -10572,6 +10601,7 @@ pub const Builder = struct {
|
||||
.base_type = array.type,
|
||||
.is_struct = false,
|
||||
.index = index,
|
||||
.name = try unit.processIdentifier(context, "indexed_array_gep"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -10606,6 +10636,7 @@ pub const Builder = struct {
|
||||
.base_type = child_pointer.type,
|
||||
.is_struct = false,
|
||||
.index = index,
|
||||
.name = try unit.processIdentifier(context, "indexed_many_pointer"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -10641,6 +10672,7 @@ pub const Builder = struct {
|
||||
.base_type = array.type,
|
||||
.is_struct = false,
|
||||
.index = index,
|
||||
.name = try unit.processIdentifier(context, "indexed_pointer_array"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -10678,6 +10710,7 @@ pub const Builder = struct {
|
||||
.base_type = child_pointer.type,
|
||||
.is_struct = false,
|
||||
.index = index,
|
||||
.name = try unit.processIdentifier(context, "many_pointer_integer"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -10699,6 +10732,36 @@ pub const Builder = struct {
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) {
|
||||
.@"struct" => |*struct_type| b: {
|
||||
if (struct_type.options.sliceable) |sliceable| {
|
||||
const load = try unit.instructions.append(context.my_allocator, .{
|
||||
.load = .{
|
||||
.value = array_like_expression,
|
||||
.type = pointer.type,
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, load);
|
||||
|
||||
const pointer_field_index = struct_type.fields.slice()[sliceable.pointer];
|
||||
const pointer_field = unit.struct_fields.get(pointer_field_index);
|
||||
const pointer_type = unit.types.get(pointer_field.type).pointer;
|
||||
const child_type_index = pointer_type.type;
|
||||
|
||||
const load_value = V{
|
||||
.value = .{
|
||||
.runtime = load,
|
||||
},
|
||||
.type = pointer.type,
|
||||
};
|
||||
const v = try builder.build_slice_indexed_access(unit, context, load_value, child_pointer.type, pointer_field.type, child_type_index, pointer_type.mutability, sliceable, index);
|
||||
break :b v;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
},
|
||||
@ -11017,6 +11080,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = try unit.processIdentifier(context, "union_for_error_gep"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, union_for_error_gep);
|
||||
@ -11234,6 +11298,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = try unit.processIdentifier(context, "union_for_error_gep"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, union_for_error_gep);
|
||||
@ -11788,6 +11853,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = field.name,
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -11927,6 +11993,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = field.name,
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -12337,6 +12404,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = try unit.processIdentifier(context, "direct_pair_gep0"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep0);
|
||||
@ -12375,6 +12443,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = try unit.processIdentifier(context, "direct_pair_gep1"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep1);
|
||||
@ -12942,6 +13011,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = try unit.processIdentifier(context, "slice_for_payload"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -13134,14 +13204,6 @@ pub const Builder = struct {
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
||||
// const catch_alloca = try builder.c
|
||||
// // const catch_alloca = try builder.createStackVariable(unit, context, catch_alloca);
|
||||
// // .stack_slot = .{
|
||||
// // .type = expression.type,
|
||||
// // },;
|
||||
// // });
|
||||
// try builder.appendInstruction(unit, context, catch_alloca);
|
||||
|
||||
const catch_type_expect = Type.Expect{ .type = error_union.type };
|
||||
const is_error = try unit.instructions.append(context.my_allocator, .{
|
||||
.extract_value = .{
|
||||
@ -13791,7 +13853,7 @@ pub const Builder = struct {
|
||||
.pointer => |pointer| switch (unit.types.get(pointer.type).*) {
|
||||
.array => |array| {
|
||||
assert(side == .right);
|
||||
assert(byte_equal(identifier, "len"));
|
||||
assert(byte_equal(identifier, length_field_name));
|
||||
break :b switch (type_expect) {
|
||||
.type => |type_index| V{
|
||||
.value = .{
|
||||
@ -13818,13 +13880,12 @@ pub const Builder = struct {
|
||||
};
|
||||
},
|
||||
.slice => |slice| {
|
||||
const slice_field: enum {
|
||||
ptr,
|
||||
len,
|
||||
} = if (byte_equal("ptr", identifier)) .ptr else if (byte_equal("len", identifier)) .len else unreachable;
|
||||
const slice_field: SliceField = inline for (@typeInfo(SliceField).Enum.fields) |field| {
|
||||
if (byte_equal(field.name, identifier)) break @enumFromInt(field.value);
|
||||
} else unreachable;
|
||||
const field_type = switch (slice_field) {
|
||||
.ptr => slice.child_pointer_type,
|
||||
.len => Type.Index.usize,
|
||||
.pointer => slice.child_pointer_type,
|
||||
.length => Type.Index.usize,
|
||||
};
|
||||
const field_index = @intFromEnum(slice_field);
|
||||
|
||||
@ -13843,6 +13904,10 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = try unit.processIdentifier(context, switch (slice_field) {
|
||||
.pointer => "slice_pointer",
|
||||
.length => "slice_length",
|
||||
}),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -13882,7 +13947,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.pointer => |child_pointer| switch (unit.types.get(child_pointer.type).*) {
|
||||
.array => |array| {
|
||||
assert(byte_equal(identifier, "len"));
|
||||
assert(byte_equal(identifier, length_field_name));
|
||||
|
||||
break :b switch (type_expect) {
|
||||
.type => |type_index| V{
|
||||
@ -13929,6 +13994,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = field.name,
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -14000,6 +14066,7 @@ pub const Builder = struct {
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = field.name,
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
@ -14832,6 +14899,73 @@ pub const Builder = struct {
|
||||
.constant_slice = constant_slice,
|
||||
};
|
||||
}
|
||||
|
||||
fn build_slice_indexed_access(builder: *Builder, unit: *Unit, context: *const Context, array_like_expression: V, sliceable_type_index: Type.Index, sliceable_pointer_type_index: Type.Index, sliceable_child_type_index: Type.Index, mutability: Mutability, sliceable: Struct.Sliceable, index: V) !V {
|
||||
const gep = try unit.instructions.append(context.my_allocator, .{
|
||||
.get_element_pointer = .{
|
||||
.pointer = array_like_expression.value.runtime,
|
||||
.base_type = sliceable_type_index,
|
||||
.is_struct = true,
|
||||
.index = .{
|
||||
.value = .{
|
||||
.@"comptime" = .{
|
||||
.constant_int = .{
|
||||
.value = sliceable.pointer,
|
||||
},
|
||||
},
|
||||
},
|
||||
.type = .u32,
|
||||
},
|
||||
.name = try unit.processIdentifier(context, "slice_pointer_access"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, gep);
|
||||
|
||||
const pointer_to_slice_pointer = try unit.getPointerType(context, .{
|
||||
.type = sliceable_pointer_type_index,
|
||||
.mutability = mutability,
|
||||
.termination = .none,
|
||||
.many = false,
|
||||
.nullable = false,
|
||||
});
|
||||
|
||||
const pointer_load = try unit.instructions.append(context.my_allocator, .{
|
||||
.load = .{
|
||||
.value = .{
|
||||
.value = .{
|
||||
.runtime = gep,
|
||||
},
|
||||
.type = pointer_to_slice_pointer,
|
||||
},
|
||||
.type = sliceable_pointer_type_index,
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, pointer_load);
|
||||
|
||||
const slice_pointer_gep = try unit.instructions.append(context.my_allocator, .{
|
||||
.get_element_pointer = .{
|
||||
.pointer = pointer_load,
|
||||
.base_type = sliceable_child_type_index,
|
||||
.is_struct = false,
|
||||
.index = index,
|
||||
.name = try unit.processIdentifier(context, "indexed_slice_gep"),
|
||||
},
|
||||
});
|
||||
try builder.appendInstruction(unit, context, slice_pointer_gep);
|
||||
|
||||
return .{
|
||||
.value = .{
|
||||
.runtime = slice_pointer_gep,
|
||||
},
|
||||
.type = try unit.getPointerType(context, .{
|
||||
.type = sliceable_child_type_index,
|
||||
.mutability = mutability,
|
||||
.many = false,
|
||||
.nullable = false,
|
||||
.termination = .none,
|
||||
}),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Enum = struct {
|
||||
|
@ -1782,7 +1782,8 @@ pub const LLVM = struct {
|
||||
const base_type = try llvm.getType(unit, context, gep.base_type);
|
||||
const in_bounds = true;
|
||||
if (gep.is_struct and gep.index.type != .u32) unreachable;
|
||||
const get_element_pointer = llvm.builder.createGEP(base_type, pointer, indices.ptr, indices.len, "gep", "gep".len, in_bounds) orelse unreachable;
|
||||
const gep_name = unit.getIdentifier(gep.name);
|
||||
const get_element_pointer = llvm.builder.createGEP(base_type, pointer, indices.ptr, indices.len, gep_name.ptr, gep_name.len, in_bounds) orelse unreachable;
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, get_element_pointer);
|
||||
return get_element_pointer;
|
||||
}
|
||||
|
@ -1606,7 +1606,10 @@ const Analyzer = struct {
|
||||
});
|
||||
|
||||
try list.append(analyzer.my_allocator, field_initialization);
|
||||
_ = try analyzer.expectToken(.operator_comma);
|
||||
switch (analyzer.peekToken()) {
|
||||
.operator_comma => analyzer.consumeToken(),
|
||||
else => {},
|
||||
}
|
||||
|
||||
break :blk .container_field_names;
|
||||
},
|
||||
@ -1708,11 +1711,21 @@ const Analyzer = struct {
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
const type_node = if (analyzer.hasTokens() and analyzer.peekToken() == .operator_left_parenthesis) b: {
|
||||
const parameters_node = if (analyzer.hasTokens() and analyzer.peekToken() == .operator_left_parenthesis) b: {
|
||||
analyzer.consumeToken();
|
||||
const result = try analyzer.typeExpression();
|
||||
_ = try analyzer.expectToken(.operator_right_parenthesis);
|
||||
break :b result;
|
||||
var list = UnpinnedArray(Node.Index){};
|
||||
while (analyzer.peekToken() != .operator_right_parenthesis) {
|
||||
const parameter_node = try analyzer.expression();
|
||||
try list.append(analyzer.my_allocator, parameter_node);
|
||||
switch (analyzer.peekToken()) {
|
||||
.operator_comma => analyzer.consumeToken(),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
analyzer.consumeToken();
|
||||
|
||||
break :b try analyzer.nodeList(list);
|
||||
} else Node.Index.null;
|
||||
|
||||
if (maybe_token_id) |_| _ = try analyzer.expectToken(.operator_left_brace);
|
||||
@ -1819,7 +1832,7 @@ const Analyzer = struct {
|
||||
.id = node_id,
|
||||
.token = token_i,
|
||||
.left = try analyzer.nodeList(node_list),
|
||||
.right = type_node,
|
||||
.right = parameters_node,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -36,12 +36,12 @@ const Executable = struct{
|
||||
link_libc_arg = "false";
|
||||
}
|
||||
|
||||
if (executable.c_source_files.len > 0) {
|
||||
assert(executable.c_source_files.len == 1);
|
||||
const argv = [_:null] ?[&:0]const u8{ compiler_path, "exe", "-main_source_file", executable.main_source_path.ptr, "-link_libc", link_libc_arg, "-name", executable.name.ptr, "-c_source_files", executable.c_source_files[0].ptr };
|
||||
if (executable.c_source_files.length > 0) {
|
||||
assert(executable.c_source_files.length == 1);
|
||||
const argv = [_:null] ?[&:0]const u8{ compiler_path, "exe", "-main_source_file", executable.main_source_path.pointer, "-link_libc", link_libc_arg, "-name", executable.name.pointer, "-c_source_files", executable.c_source_files[0].pointer };
|
||||
try std.os.execute(path = compiler_path, argv = argv.&, env = std.start.environment_values);
|
||||
} else {
|
||||
const argv = [_:null] ?[&:0]const u8{ compiler_path, "exe", "-main_source_file", executable.main_source_path.ptr, "-link_libc", link_libc_arg, "-name", executable.name.ptr };
|
||||
const argv = [_:null] ?[&:0]const u8{ compiler_path, "exe", "-main_source_file", executable.main_source_path.pointer, "-link_libc", link_libc_arg, "-name", executable.name.pointer };
|
||||
try std.os.execute(path = compiler_path, argv = argv.&, env = std.start.environment_values);
|
||||
}
|
||||
} else {
|
||||
|
@ -33,3 +33,7 @@ const TestFunction = struct{
|
||||
name: []const u8,
|
||||
function: &const fn () *!void,
|
||||
};
|
||||
|
||||
const StructOptions = struct{
|
||||
sliceable: bool = false,
|
||||
};
|
||||
|
@ -44,10 +44,10 @@ const FileDescriptor = struct{
|
||||
};
|
||||
|
||||
const read = fn(file_descriptor: FileDescriptor, bytes: []u8) ReadError!usize {
|
||||
if (bytes.len > 0) {
|
||||
if (bytes.length > 0) {
|
||||
switch (current) {
|
||||
.linux => {
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.length);
|
||||
const syscall_result = system.read(file_descriptor, bytes);
|
||||
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => unreachable,
|
||||
@ -55,7 +55,7 @@ const FileDescriptor = struct{
|
||||
return byte_count;
|
||||
},
|
||||
.macos => {
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.length);
|
||||
const syscall_result = system.read(file_descriptor, bytes);
|
||||
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => unreachable,
|
||||
@ -76,16 +76,16 @@ const FileDescriptor = struct{
|
||||
const write = fn (file_descriptor: FileDescriptor, bytes: []const u8) WriteError!usize {
|
||||
switch (current) {
|
||||
.linux => {
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||
const syscall_result = system.write(file_descriptor.handle, bytes[0..len]);
|
||||
const length: usize = #min(max_file_operation_byte_count, bytes.length);
|
||||
const syscall_result = system.write(file_descriptor.handle, bytes[0..length]);
|
||||
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => return WriteError.write_failed,
|
||||
};
|
||||
return byte_count;
|
||||
},
|
||||
.macos => {
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||
const syscall_result = system.write(file_descriptor.handle, bytes.ptr, bytes.len);
|
||||
const length: usize = #min(max_file_operation_byte_count, bytes.length);
|
||||
const syscall_result = system.write(file_descriptor.handle, bytes.pointer, length);
|
||||
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => return WriteError.write_failed,
|
||||
};
|
||||
@ -170,7 +170,7 @@ const free_virtual_memory = fn(bytes: []const u8) FreeError!void {
|
||||
};
|
||||
},
|
||||
.macos => {
|
||||
const syscall_result = system.munmap(bytes.ptr, bytes.len);
|
||||
const syscall_result = system.munmap(bytes.pointer, bytes.length);
|
||||
_ = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => unreachable,
|
||||
};
|
||||
@ -218,19 +218,19 @@ const current_executable_path = fn(buffer: [:0]u8) CurrentExecutablePath![]u8 {
|
||||
},
|
||||
.macos => {
|
||||
var symlink_path_buffer: [max_path_byte_count:0]u8 = undefined;
|
||||
var symlink_path_len: u32 = symlink_path_buffer.len + 1;
|
||||
var symlink_path_len: u32 = symlink_path_buffer.length + 1;
|
||||
const ns_result = c._NSGetExecutablePath(symlink_path_buffer.&, symlink_path_len.&);
|
||||
if (ns_result == 0) {
|
||||
const symlink_path = symlink_path_buffer[0..symlink_path_len];
|
||||
if (c.realpath(symlink_path.ptr, buffer.ptr)) |result| {
|
||||
if (c.realpath(symlink_path.pointer, buffer.pointer)) |result| {
|
||||
var i: usize = 0;
|
||||
while (i < buffer.len) {
|
||||
while (i < buffer.length) {
|
||||
if (result[i] == 0) {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
assert(i < buffer.len);
|
||||
assert(i < buffer.length);
|
||||
|
||||
const r: []u8 = result[0..i];
|
||||
return r;
|
||||
@ -373,7 +373,7 @@ const PollFileDescriptor = system.PollFileDescriptor;
|
||||
const poll = fn(file_descriptors: []PollFileDescriptor, timeout: s32) ?usize {
|
||||
switch (current) {
|
||||
.linux => {
|
||||
if (linux.unwrap_syscall(syscall_result = linux.poll(file_descriptors = file_descriptors.ptr, file_descriptor_count = file_descriptors.len, timeout = timeout))) |result| {
|
||||
if (linux.unwrap_syscall(syscall_result = linux.poll(file_descriptors = file_descriptors.pointer, file_descriptor_count = file_descriptors.length, timeout = timeout))) |result| {
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
|
@ -873,12 +873,12 @@ const mmap = fn(address: ?[&]u8, length: usize, protection_flags: ProtectionFlag
|
||||
}
|
||||
|
||||
const munmap = fn(bytes: []const u8) usize {
|
||||
const result = #syscall(#cast(Syscall.munmap), #cast(bytes.ptr), bytes.len);
|
||||
const result = #syscall(#cast(Syscall.munmap), #cast(bytes.pointer), bytes.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
const readlink = fn(file_path: [&:0]const u8, bytes: []u8) usize {
|
||||
const result = #syscall(#cast(Syscall.readlink), #cast(file_path), #cast(bytes.ptr), bytes.len);
|
||||
const result = #syscall(#cast(Syscall.readlink), #cast(file_path), #cast(bytes.pointer), bytes.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -913,12 +913,12 @@ const openat = fn(directory_file_descriptor: FileDescriptor, path: [&:0]const u8
|
||||
}
|
||||
|
||||
const read = fn(file_descriptor: FileDescriptor, bytes: []u8) usize {
|
||||
const result = #syscall(#cast(Syscall.read), #cast(file_descriptor), #cast(bytes.ptr), bytes.len);
|
||||
const result = #syscall(#cast(Syscall.read), #cast(file_descriptor), #cast(bytes.pointer), bytes.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
const write = fn(file_descriptor: FileDescriptor, bytes: []const u8) usize {
|
||||
const result = #syscall(#cast(Syscall.write), #cast(file_descriptor), #cast(bytes.ptr), bytes.len);
|
||||
const result = #syscall(#cast(Syscall.write), #cast(file_descriptor), #cast(bytes.pointer), bytes.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ const print = fn(bytes: []const u8) void {
|
||||
}
|
||||
|
||||
const format_usize = fn(n: usize, buffer: &[65]u8) []u8 {
|
||||
var index: usize = buffer.len;
|
||||
var index: usize = buffer.length;
|
||||
var absolute = n;
|
||||
|
||||
while (true) {
|
||||
@ -53,7 +53,7 @@ const format_usize = fn(n: usize, buffer: &[65]u8) []u8 {
|
||||
const print_usize = fn(n: usize) void {
|
||||
var buffer: [65]u8 = undefined;
|
||||
const bytes = format_usize(n, buffer = buffer.&);
|
||||
assert(bytes.len < buffer.len);
|
||||
assert(bytes.length < buffer.length);
|
||||
const file_descriptor = os.StdFileDescriptor.get(descriptor = .stdout);
|
||||
const file_writer = FileWriter{
|
||||
.descriptor = file_descriptor,
|
||||
@ -79,11 +79,11 @@ const Allocator = struct {
|
||||
}
|
||||
|
||||
const free = fn (allocator: &Allocator, bytes: []const u8) Allocator.Error!void {
|
||||
_ = try allocator.handler(allocator, old_ptr = bytes.ptr, old_size = bytes.len, new_size = 0, alignment = 0);
|
||||
_ = try allocator.handler(allocator, old_ptr = bytes.pointer, old_size = bytes.length, new_size = 0, alignment = 0);
|
||||
}
|
||||
|
||||
const duplicate_bytes = fn (allocator: &Allocator, bytes: []const u8) Allocator.Error![]u8 {
|
||||
const result = try allocator.allocate(size = bytes.len, alignment = 0);
|
||||
const result = try allocator.allocate(size = bytes.length, alignment = 0);
|
||||
copy_bytes(destination = result, source = bytes);
|
||||
return result;
|
||||
}
|
||||
@ -154,18 +154,18 @@ const FileWriter = struct{
|
||||
const write_all = fn(file_writer: FileWriter, bytes: []const u8) Writer.Error!void {
|
||||
var bytes_written: usize = 0;
|
||||
|
||||
while (bytes_written < bytes.len) {
|
||||
while (bytes_written < bytes.length) {
|
||||
const iteration_written_byte_count = try file_writer.write(bytes = bytes[bytes_written..]);
|
||||
bytes_written += iteration_written_byte_count;
|
||||
}
|
||||
|
||||
assert(bytes_written == bytes.len);
|
||||
assert(bytes_written == bytes.length);
|
||||
}
|
||||
};
|
||||
|
||||
const copy_bytes = fn(destination: []u8, source: []const u8) void {
|
||||
assert(ok = destination.len == source.len);
|
||||
for (0..destination.len) |i| {
|
||||
assert(ok = destination.length == source.length);
|
||||
for (0..destination.length) |i| {
|
||||
destination[i] = source[i];
|
||||
}
|
||||
}
|
||||
@ -173,14 +173,14 @@ const copy_bytes = fn(destination: []u8, source: []const u8) void {
|
||||
const concatenate_bytes = fn(allocator: &Allocator, slices: []const []const u8) Allocator.Error![]u8 {
|
||||
var total_byte_count: usize = 0;
|
||||
for (slices) |slice| {
|
||||
total_byte_count += slice.len;
|
||||
total_byte_count += slice.length;
|
||||
}
|
||||
|
||||
const bytes = try allocator.allocate(total_byte_count, 1);
|
||||
var offset: usize = 0;
|
||||
for (slice) |slice| {
|
||||
copy_bytes(bytes[offset..][0..slice.len], slice);
|
||||
offset += slice.len;
|
||||
copy_bytes(bytes[offset..][0..slice.length], slice);
|
||||
offset += slice.length;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
|
@ -5,7 +5,7 @@ const count_slice_byte_count = fn(slices: []const []const u8) usize {
|
||||
var byte_count: usize = 0;
|
||||
|
||||
for (slices) |slice| {
|
||||
byte_count += slice.len;
|
||||
byte_count += slice.length;
|
||||
}
|
||||
|
||||
return byte_count;
|
||||
@ -27,7 +27,7 @@ const Error = error{
|
||||
const main = fn () Error!void {
|
||||
const a = [_]u8{1, 1, 4, 5, 6};
|
||||
const b = [_]u8{1, 4, 6};
|
||||
const expected_result: usize = a.len + b.len;
|
||||
const expected_result: usize = a.length + b.length;
|
||||
const result = count_slice_byte_count(slices = .{a.&, b.&}.&);
|
||||
print_values(slice = a.&);
|
||||
if (expected_result - result != 0) {
|
||||
|
@ -8,8 +8,8 @@ const Error = error{
|
||||
const main = fn() Error!void {
|
||||
var buffer: [65]u8 = undefined;
|
||||
const slice = foo(5, buffer.&);
|
||||
assert(slice.len + 5 == buffer.len);
|
||||
const result: u32 = #cast(slice.len + 5 - buffer.len);
|
||||
assert(slice.length + 5 == buffer.length);
|
||||
const result: u32 = #cast(slice.length + 5 - buffer.length);
|
||||
if (result != 0) {
|
||||
return Error.unexpected_result;
|
||||
}
|
||||
|
30
test/standalone/sliceable/main.nat
Normal file
30
test/standalone/sliceable/main.nat
Normal file
@ -0,0 +1,30 @@
|
||||
const std = #import("std");
|
||||
const expect = std.testing.expect;
|
||||
const assert = std.assert;
|
||||
|
||||
const Foo = struct(.{ .sliceable = true }) {
|
||||
pointer: [&]u8,
|
||||
length: u32,
|
||||
capacity: u32,
|
||||
|
||||
const add = fn (foo: &Foo, item: u8) void {
|
||||
const index = foo.length;
|
||||
assert(index < foo.capacity);
|
||||
foo.length += 1;
|
||||
foo[index] = item;
|
||||
}
|
||||
};
|
||||
|
||||
const main = fn () *!void {
|
||||
var foo = [1]u8{0};
|
||||
var s = Foo{
|
||||
.pointer = foo.&,
|
||||
.length = 0,
|
||||
.capacity = 1,
|
||||
};
|
||||
|
||||
s.add(5);
|
||||
|
||||
try expect(s.length == 1);
|
||||
try expect(foo[0] == 5);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user