More self-hosted work

This commit is contained in:
David Gonzalez Martin 2024-04-23 18:11:57 -06:00
parent eb31e4b663
commit b88f3bbba0
3 changed files with 251 additions and 66 deletions

View File

@ -3431,6 +3431,7 @@ pub const Type = union(enum) {
type: Type.Index, type: Type.Index,
termination: Termination, termination: Termination,
}, },
cast: Type.Index,
}; };
const Error = struct { const Error = struct {
@ -4605,7 +4606,7 @@ pub const Builder = struct {
} }
} }
fn resolveIntrinsic(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, node_index: Node.Index) anyerror!V { fn resolveIntrinsic(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, node_index: Node.Index, side: Side) anyerror!V {
const node = unit.getNode(node_index); const node = unit.getNode(node_index);
const intrinsic_id: IntrinsicId = @enumFromInt(Node.unwrap(node.right)); const intrinsic_id: IntrinsicId = @enumFromInt(Node.unwrap(node.right));
const argument_node_list = unit.getNodeList(node.left); const argument_node_list = unit.getNodeList(node.left);
@ -4702,12 +4703,18 @@ pub const Builder = struct {
.cast => { .cast => {
assert(argument_node_list.len == 1); assert(argument_node_list.len == 1);
const argument_node_index = argument_node_list[0]; const argument_node_index = argument_node_list[0];
const cast_type_expect = Type.Expect{
.cast = switch (type_expect) {
.type => |type_index| type_index,
else => |t| @panic(@tagName(t)),
},
};
// TODO: depends? .right is not always the right choice // TODO: depends? .right is not always the right choice
const v = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, argument_node_index, .right); const v = try builder.resolveRuntimeValue(unit, context, cast_type_expect, argument_node_index, side);
switch (type_expect) { switch (type_expect) {
.type => |type_index| { .type => |type_index| {
const cast_id = try builder.resolveCast(unit, context, type_index, v); const cast_id = try builder.resolveCast(unit, context, type_index, v, side);
switch (cast_id) { switch (cast_id) {
.array_bitcast_to_integer => switch (v.value) { .array_bitcast_to_integer => switch (v.value) {
.@"comptime" => |ct| switch (ct) { .@"comptime" => |ct| switch (ct) {
@ -4734,8 +4741,61 @@ pub const Builder = struct {
else => unreachable, else => unreachable,
} }
}, },
.string_literal => |hash| {
const string_literal = unit.getIdentifier(hash);
var value: u64 = 0;
for (string_literal, 0..) |byte, i| {
value |= @as(u64, byte) << @as(u6, @intCast(i * 8));
}
return V{
.value = .{
.@"comptime" = .{
.constant_int = .{
.value = value,
},
},
},
.type = switch (unit.types.get(type_index).*) {
.pointer => |pointer| pointer.type,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
};
},
else => |t| @panic(@tagName(t)),
},
.runtime => {
const stack = try builder.createStackVariable(unit, context, type_index, null);
const destination = V{
.value = .{ .runtime = stack },
.type = try unit.getPointerType(context, .{
.type = type_index,
.many = false,
.termination = .none,
.mutability = .@"var",
.nullable = false,
}),
};
const store = try unit.instructions.append(context.my_allocator, .{
.store = .{
.destination = destination,
.source = v,
},
});
try builder.appendInstruction(unit, context, store);
const load = try unit.instructions.append(context.my_allocator, .{
.load = .{
.value = destination,
.type = type_index,
},
});
try builder.appendInstruction(unit, context, load);
return V{
.value = .{ .runtime = load },
.type = type_index,
};
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
else => { else => {
@ -5287,7 +5347,7 @@ pub const Builder = struct {
} }
} }
fn resolveCast(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index, value: V) !Instruction.Cast.Id { fn resolveCast(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index, value: V, side: Side) !Instruction.Cast.Id {
_ = builder; // autofix _ = builder; // autofix
_ = context; // autofix _ = context; // autofix
assert(type_index != value.type); assert(type_index != value.type);
@ -5329,6 +5389,20 @@ pub const Builder = struct {
return .pointer_source_type_to_destination_type; return .pointer_source_type_to_destination_type;
} }
}, },
.array => |array| {
const array_size = array.count * unit.types.get(array.type).getAbiSize(unit);
switch (side) {
.right => {
const destination_type_size = unit.types.get(destination_pointer.type).getAbiSize(unit);
if (array_size == destination_type_size) {
return .array_bitcast_to_integer;
} else {
unreachable;
}
},
.left => unreachable,
}
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
}, },
@ -6630,6 +6704,7 @@ pub const Builder = struct {
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
}, },
.cast => return v,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
} else { } else {
@ -9887,7 +9962,7 @@ pub const Builder = struct {
const result = try builder.resolveIdentifier(unit, context, type_expect, identifier, .{}, side, &.{}); const result = try builder.resolveIdentifier(unit, context, type_expect, identifier, .{}, side, &.{});
break :block result; break :block result;
}, },
.intrinsic => try builder.resolveIntrinsic(unit, context, type_expect, node_index), .intrinsic => try builder.resolveIntrinsic(unit, context, type_expect, node_index, side),
.pointer_dereference => block: { .pointer_dereference => block: {
// TODO: // TODO:
const pointer_type_expect = switch (type_expect) { const pointer_type_expect = switch (type_expect) {
@ -9905,6 +9980,7 @@ pub const Builder = struct {
}; };
break :b result; break :b result;
}, },
.cast => Type.Expect.none,
else => unreachable, else => unreachable,
}; };
@ -9948,7 +10024,7 @@ pub const Builder = struct {
.right => switch (unit.types.get(pointer_like_value.type).*) { .right => switch (unit.types.get(pointer_like_value.type).*) {
.pointer => |pointer| right: { .pointer => |pointer| right: {
const load_type = switch (type_expect) { const load_type = switch (type_expect) {
.none => b: { .none, .cast => b: {
const pointer_element_type = pointer.type; const pointer_element_type = pointer.type;
break :b pointer_element_type; break :b pointer_element_type;
}, },
@ -9971,6 +10047,10 @@ pub const Builder = struct {
.type = load_type, .type = load_type,
}; };
}, },
.integer => switch (type_expect) {
.type => |type_index| if (type_index == pointer_like_value.type) pointer_like_value else unreachable,
else => |t| @panic(@tagName(t)),
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
}; };
@ -10157,7 +10237,7 @@ pub const Builder = struct {
.integer => |int| switch (int.kind) { .integer => |int| switch (int.kind) {
.materialized_int, .comptime_int, .bool => { .materialized_int, .comptime_int, .bool => {
const right_expect_type: Type.Expect = switch (type_expect) { const right_expect_type: Type.Expect = switch (type_expect) {
.none => switch (left_value.type) { .none, .cast => switch (left_value.type) {
.comptime_int => type_expect, .comptime_int => type_expect,
else => Type.Expect{ else => Type.Expect{
.type = left_value.type, .type = left_value.type,
@ -10281,7 +10361,7 @@ pub const Builder = struct {
assert(left_value.type == right_value.type); assert(left_value.type == right_value.type);
const type_index = switch (type_expect) { const type_index = switch (type_expect) {
.none => switch (binary_operation_id) { .none, .cast => switch (binary_operation_id) {
.bit_and, .bit_and,
.bit_or, .bit_or,
.bit_xor, .bit_xor,
@ -10727,6 +10807,43 @@ pub const Builder = struct {
switch (len_expression.value) { switch (len_expression.value) {
.@"comptime" => { .@"comptime" => {
const pointer_value = switch (unit.types.get(expression_to_slice.type).*) { const pointer_value = switch (unit.types.get(expression_to_slice.type).*) {
.slice => |slice| slice: {
const extract_pointer = try unit.instructions.append(context.my_allocator, .{
.extract_value = .{
.expression = expression_to_slice,
.index = 0,
},
});
try builder.appendInstruction(unit, context, extract_pointer);
const gep = try unit.instructions.append(context.my_allocator, .{
.get_element_pointer = .{
.pointer = extract_pointer,
.index = range_start,
.base_type = slice.child_type,
.name = try unit.processIdentifier(context, "slice_comptime_expression_slice"),
.is_struct = false,
},
});
try builder.appendInstruction(unit, context, gep);
break :slice V{
.value = .{
.runtime = gep,
},
.type = try unit.getPointerType(context, .{
.type = try unit.getArrayType(context, .{
.type = slice.child_type,
.count = len_expression.value.@"comptime".constant_int.value,
.termination = slice.termination,
}),
.termination = .none,
.mutability = slice.mutability,
.many = true,
.nullable = false,
}),
};
},
.pointer => |pointer| switch (pointer.many) { .pointer => |pointer| switch (pointer.many) {
true => unreachable, true => unreachable,
false => switch (unit.types.get(pointer.type).*) { false => switch (unit.types.get(pointer.type).*) {
@ -10852,6 +10969,7 @@ pub const Builder = struct {
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
.none => break :block pointer_value,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
}, },
@ -11458,6 +11576,46 @@ pub const Builder = struct {
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
.cast => |type_index| switch (unit.types.get(type_index).*) {
.pointer => switch (side) {
.left => unreachable,
.right => blk: {
const string_literal = try unit.fixupStringLiteral(context, node.token);
const hash = try unit.processIdentifier(context, string_literal);
const ty = try unit.getArrayType(context, .{
.type = .u8,
.count = string_literal.len,
.termination = .none,
});
break :blk V{
.value = .{
.@"comptime" = .{
.string_literal = hash,
},
},
.type = ty,
};
},
},
else => |t| @panic(@tagName(t)),
},
.none => none: {
const string_literal = try unit.fixupStringLiteral(context, node.token);
const hash = try unit.processIdentifier(context, string_literal);
const ty = try unit.getArrayType(context, .{
.type = .u8,
.count = string_literal.len,
.termination = .none,
});
break :none V{
.value = .{
.@"comptime" = .{
.string_literal = hash,
},
},
.type = ty,
};
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
.if_else => try builder.resolveIfElse(unit, context, type_expect, node_index), .if_else => try builder.resolveIfElse(unit, context, type_expect, node_index),
@ -12450,7 +12608,7 @@ pub const Builder = struct {
.@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) {
.error_union => |error_union| { .error_union => |error_union| {
switch (type_expect) { switch (type_expect) {
.none => {}, .none, .cast => {},
.type => |type_index| { .type => |type_index| {
switch (try builder.typecheck(unit, context, type_index, error_union.type)) { switch (try builder.typecheck(unit, context, type_index, error_union.type)) {
.success => {}, .success => {},
@ -14081,7 +14239,7 @@ pub const Builder = struct {
.intrinsic => { .intrinsic => {
_ = try builder.resolveIntrinsic(unit, context, Type.Expect{ _ = try builder.resolveIntrinsic(unit, context, Type.Expect{
.type = .void, .type = .void,
}, statement_node_index); }, statement_node_index, .right);
}, },
.constant_symbol_declaration, .constant_symbol_declaration,
.variable_symbol_declaration, .variable_symbol_declaration,
@ -15448,6 +15606,25 @@ pub const Builder = struct {
} else unreachable, } else unreachable,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
.string_literal => |hash| if (byte_equal(identifier, length_field_name)) switch (type_expect) {
.type => |type_index| switch (unit.types.get(type_index).*) {
.integer => |*integer| switch (integer.kind) {
.materialized_int => V{
.value = .{
.@"comptime" = .{
.constant_int = .{
.value = unit.getIdentifier(hash).len,
},
},
},
.type = type_index,
},
else => |t| @panic(@tagName(t)),
},
else => |t| @panic(@tagName(t)),
},
else => |t| @panic(@tagName(t)),
} else unreachable,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
.runtime => |_| b: { .runtime => |_| b: {
@ -15817,6 +15994,7 @@ pub const Builder = struct {
switch (type_expect) { switch (type_expect) {
.none => return result, .none => return result,
.cast => return result,
.type => |ti| { .type => |ti| {
const typecheck_result = try builder.typecheck(unit, context, ti, result.type); const typecheck_result = try builder.typecheck(unit, context, ti, result.type);
switch (typecheck_result) { switch (typecheck_result) {

View File

@ -1597,7 +1597,7 @@ pub const LLVM = struct {
}, },
.bool => b: { .bool => b: {
const flags = LLVM.DebugInfo.Node.Flags{ const flags = LLVM.DebugInfo.Node.Flags{
.visibility = .none, .visibility = .private,
.forward_declaration = false, .forward_declaration = false,
.apple_block = false, .apple_block = false,
.block_by_ref_struct = false, .block_by_ref_struct = false,
@ -1616,7 +1616,7 @@ pub const LLVM = struct {
.introduced_virtual = false, .introduced_virtual = false,
.bit_field = false, .bit_field = false,
.no_return = false, .no_return = false,
.type_pass_by_value = false, .type_pass_by_value = true,
.type_pass_by_reference = false, .type_pass_by_reference = false,
.enum_class = false, .enum_class = false,
.thunk = false, .thunk = false,
@ -1625,7 +1625,7 @@ pub const LLVM = struct {
.little_endian = false, .little_endian = false,
.all_calls_described = false, .all_calls_described = false,
}; };
const boolean_type = llvm.debug_info_builder.createBasicType("bool", "bool".len, 1, .boolean, flags) orelse unreachable; const boolean_type = llvm.debug_info_builder.createBasicType("bool", "bool".len, 8, .boolean, flags) orelse unreachable;
break :b boolean_type; break :b boolean_type;
}, },
.@"enum" => |*enum_type| b: { .@"enum" => |*enum_type| b: {

View File

@ -19,7 +19,7 @@ const Parser = struct{
const pointer = parser.text; const pointer = parser.text;
while (parser.index < length) { while (parser.index < length) {
const ch = pointer[parser.index]; const ch = pointer[parser.index];
const new_line = ch == '\r'; const new_line = ch == '\n';
const is_space = ch == ' ' or ch == '\t' or new_line or ch == '\r'; const is_space = ch == ' ' or ch == '\t' or new_line or ch == '\r';
if (new_line) { if (new_line) {
parser.current_line += 1; parser.current_line += 1;
@ -46,60 +46,67 @@ const parse = fn (arena: &Arena, bytes: []const u8) *!void {
.length = length, .length = length,
}; };
//var index: u32 = 0; while (parser.index < length) {
//while (index < length) { parser.skip_whitespace();
// parser.skip_whitespace();
// if (index == length) { const current_index = parser.index;
// break; if (current_index == length) {
// } break;
}
// const slice_8 = bytes[index..][0..8]; const slice = bytes[current_index..];
// const slice_4 = bytes[index..][0..4]; const is_const = byte_equal(slice[0.."const".length], "const");
// const chunk_8: u64 = #cast(slice_8.@); const is_var = byte_equal(slice[0.."var".length], "var");
// const chunk_4: u64 = #cast(slice_4.@); const is_test = byte_equal(slice[0.."test".length], "test");
// const comptime_mask: u64 = #cast("comptime".@); const is_comptime = byte_equal(slice[0.."comptime".length], "comptime");
// const test_mask: u32 = #cast("test").@; if (is_const) {
// const const_mask: u32 = #cast("const").@; const space_index: u32 = "const".length;
// const var_mask: u32 = #cast("var ").@; const ch = slice[space_index];
// const is_comptime = chunk_8 == comptime_mask; const next_ch = slice[space_index + 1];
// const is_test = chunk_4 == test_mask; const is_normal_space = (ch == ' ' or ch == '\n') or (ch == '\t' or ch == '\r');
// const is_const = chunk_4 == const_mask; const is_comment = ch == '/' and next_ch == '/';
// const is_var = (chunk_4 & 0xffffff) == (var_mask & 0xffffff); const is_space = is_normal_space or is_comment;
if (!is_space) {
// const is_valid = is_comptime or is_test or is_const or is_var; exit(1);
}
// if (is_valid) { exit(0);
// exit(0); } else if (is_var) {
// } else { const space_index: u32 = "var".length;
// exit(1); const ch = slice[space_index];
// } const next_ch = slice[space_index + 1];
//} const is_normal_space = (ch == ' ' or ch == '\n') or (ch == '\t' or ch == '\r');
const is_comment = ch == '/' and next_ch == '/';
//var index: u32 = 0; const is_space = is_normal_space or is_comment;
//while (index + 64 < length) { if (!is_space) {
// var i = index; exit(1);
// const top = index + max_initial_keyword_len + 1; }
// var space: u32 = 0; exit(0);
} else if (is_test) {
// while (i < top) { const space_index: u32 = "test".length;
// const is_space = bytes[i] == ' '; const ch = slice[space_index];
// const is_space_int: u32 = #cast(is_space); const next_ch = slice[space_index + 1];
// const space_mask = 0 -% is_space_int; const is_normal_space = (ch == ' ' or ch == '\n') or (ch == '\t' or ch == '\r');
// space |= (1 << i) & space_mask; const is_comment = ch == '/' and next_ch == '/';
// i += 1; const is_space = is_normal_space or is_comment;
// } if (!is_space) {
exit(1);
// if (space == 0) { }
// unreachable; exit(0);
// } } else if (is_comptime) {
const space_index: u32 = "comptime".length;
// const word_byte_count = #trailing_zeroes(space); const ch = slice[space_index];
// const word = bytes[index..][0..word_byte_count]; const next_ch = slice[space_index + 1];
const is_normal_space = (ch == ' ' or ch == '\n') or (ch == '\t' or ch == '\r');
const is_comment = ch == '/' and next_ch == '/';
// break; const is_space = is_normal_space or is_comment;
//} if (!is_space) {
exit(1);
}
exit(0);
} else {
exit(1);
}
}
} }
const FileStartToken = enum{ const FileStartToken = enum{