From b88f3bbba00cdc5f9d7628c255a59985b1a69cc0 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Tue, 23 Apr 2024 18:11:57 -0600 Subject: [PATCH] More self-hosted work --- bootstrap/Compilation.zig | 198 +++++++++++++++++++++++++++++++++++-- bootstrap/backend/llvm.zig | 6 +- src/main.nat | 113 +++++++++++---------- 3 files changed, 251 insertions(+), 66 deletions(-) diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index 9f7e0ef..c518100 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -3431,6 +3431,7 @@ pub const Type = union(enum) { type: Type.Index, termination: Termination, }, + cast: Type.Index, }; 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 intrinsic_id: IntrinsicId = @enumFromInt(Node.unwrap(node.right)); const argument_node_list = unit.getNodeList(node.left); @@ -4702,12 +4703,18 @@ pub const Builder = struct { .cast => { assert(argument_node_list.len == 1); 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 - 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) { .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) { .array_bitcast_to_integer => switch (v.value) { .@"comptime" => |ct| switch (ct) { @@ -4734,8 +4741,61 @@ pub const Builder = struct { 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)), }, + .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 => { @@ -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 _ = context; // autofix assert(type_index != value.type); @@ -5329,6 +5389,20 @@ pub const Builder = struct { 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)), } }, @@ -6630,6 +6704,7 @@ pub const Builder = struct { else => |t| @panic(@tagName(t)), } }, + .cast => return v, else => |t| @panic(@tagName(t)), } } else { @@ -9887,7 +9962,7 @@ pub const Builder = struct { const result = try builder.resolveIdentifier(unit, context, type_expect, identifier, .{}, side, &.{}); 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: { // TODO: const pointer_type_expect = switch (type_expect) { @@ -9905,6 +9980,7 @@ pub const Builder = struct { }; break :b result; }, + .cast => Type.Expect.none, else => unreachable, }; @@ -9948,7 +10024,7 @@ pub const Builder = struct { .right => switch (unit.types.get(pointer_like_value.type).*) { .pointer => |pointer| right: { const load_type = switch (type_expect) { - .none => b: { + .none, .cast => b: { const pointer_element_type = pointer.type; break :b pointer_element_type; }, @@ -9971,6 +10047,10 @@ pub const Builder = struct { .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)), }, }; @@ -10157,7 +10237,7 @@ pub const Builder = struct { .integer => |int| switch (int.kind) { .materialized_int, .comptime_int, .bool => { const right_expect_type: Type.Expect = switch (type_expect) { - .none => switch (left_value.type) { + .none, .cast => switch (left_value.type) { .comptime_int => type_expect, else => Type.Expect{ .type = left_value.type, @@ -10281,7 +10361,7 @@ pub const Builder = struct { assert(left_value.type == right_value.type); const type_index = switch (type_expect) { - .none => switch (binary_operation_id) { + .none, .cast => switch (binary_operation_id) { .bit_and, .bit_or, .bit_xor, @@ -10727,6 +10807,43 @@ pub const Builder = struct { switch (len_expression.value) { .@"comptime" => { 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) { true => unreachable, false => switch (unit.types.get(pointer.type).*) { @@ -10852,6 +10969,7 @@ pub const Builder = struct { }, else => |t| @panic(@tagName(t)), }, + .none => break :block pointer_value, else => |t| @panic(@tagName(t)), } }, @@ -11458,6 +11576,46 @@ pub const Builder = struct { }, 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)), }, .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) { .error_union => |error_union| { switch (type_expect) { - .none => {}, + .none, .cast => {}, .type => |type_index| { switch (try builder.typecheck(unit, context, type_index, error_union.type)) { .success => {}, @@ -14081,7 +14239,7 @@ pub const Builder = struct { .intrinsic => { _ = try builder.resolveIntrinsic(unit, context, Type.Expect{ .type = .void, - }, statement_node_index); + }, statement_node_index, .right); }, .constant_symbol_declaration, .variable_symbol_declaration, @@ -15448,6 +15606,25 @@ pub const Builder = struct { } else unreachable, 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)), }, .runtime => |_| b: { @@ -15817,6 +15994,7 @@ pub const Builder = struct { switch (type_expect) { .none => return result, + .cast => return result, .type => |ti| { const typecheck_result = try builder.typecheck(unit, context, ti, result.type); switch (typecheck_result) { diff --git a/bootstrap/backend/llvm.zig b/bootstrap/backend/llvm.zig index 08f9f00..8784efb 100644 --- a/bootstrap/backend/llvm.zig +++ b/bootstrap/backend/llvm.zig @@ -1597,7 +1597,7 @@ pub const LLVM = struct { }, .bool => b: { const flags = LLVM.DebugInfo.Node.Flags{ - .visibility = .none, + .visibility = .private, .forward_declaration = false, .apple_block = false, .block_by_ref_struct = false, @@ -1616,7 +1616,7 @@ pub const LLVM = struct { .introduced_virtual = false, .bit_field = false, .no_return = false, - .type_pass_by_value = false, + .type_pass_by_value = true, .type_pass_by_reference = false, .enum_class = false, .thunk = false, @@ -1625,7 +1625,7 @@ pub const LLVM = struct { .little_endian = 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; }, .@"enum" => |*enum_type| b: { diff --git a/src/main.nat b/src/main.nat index 1e89b6c..13c741c 100644 --- a/src/main.nat +++ b/src/main.nat @@ -19,7 +19,7 @@ const Parser = struct{ const pointer = parser.text; while (parser.index < length) { 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'; if (new_line) { parser.current_line += 1; @@ -46,60 +46,67 @@ const parse = fn (arena: &Arena, bytes: []const u8) *!void { .length = length, }; - //var index: u32 = 0; - //while (index < length) { - // parser.skip_whitespace(); + while (parser.index < length) { + parser.skip_whitespace(); - // if (index == length) { - // break; - // } + const current_index = parser.index; + if (current_index == length) { + break; + } - // const slice_8 = bytes[index..][0..8]; - // const slice_4 = bytes[index..][0..4]; - // const chunk_8: u64 = #cast(slice_8.@); - // const chunk_4: u64 = #cast(slice_4.@); - // const comptime_mask: u64 = #cast("comptime".@); - // const test_mask: u32 = #cast("test").@; - // const const_mask: u32 = #cast("const").@; - // const var_mask: u32 = #cast("var ").@; - // const is_comptime = chunk_8 == comptime_mask; - // const is_test = chunk_4 == test_mask; - // const is_const = chunk_4 == const_mask; - // const is_var = (chunk_4 & 0xffffff) == (var_mask & 0xffffff); - - // const is_valid = is_comptime or is_test or is_const or is_var; - - // if (is_valid) { - // exit(0); - // } else { - // exit(1); - // } - //} - - //var index: u32 = 0; - //while (index + 64 < length) { - // var i = index; - // const top = index + max_initial_keyword_len + 1; - // var space: u32 = 0; - - // while (i < top) { - // const is_space = bytes[i] == ' '; - // const is_space_int: u32 = #cast(is_space); - // const space_mask = 0 -% is_space_int; - // space |= (1 << i) & space_mask; - // i += 1; - // } - - // if (space == 0) { - // unreachable; - // } - - // const word_byte_count = #trailing_zeroes(space); - // const word = bytes[index..][0..word_byte_count]; - - - // break; - //} + const slice = bytes[current_index..]; + const is_const = byte_equal(slice[0.."const".length], "const"); + const is_var = byte_equal(slice[0.."var".length], "var"); + const is_test = byte_equal(slice[0.."test".length], "test"); + const is_comptime = byte_equal(slice[0.."comptime".length], "comptime"); + if (is_const) { + const space_index: u32 = "const".length; + 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 == '/'; + const is_space = is_normal_space or is_comment; + if (!is_space) { + exit(1); + } + exit(0); + } else if (is_var) { + const space_index: u32 = "var".length; + 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 == '/'; + const is_space = is_normal_space or is_comment; + if (!is_space) { + exit(1); + } + exit(0); + } else if (is_test) { + const space_index: u32 = "test".length; + 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 == '/'; + const is_space = is_normal_space or is_comment; + if (!is_space) { + exit(1); + } + exit(0); + } else if (is_comptime) { + const space_index: u32 = "comptime".length; + 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 == '/'; + const is_space = is_normal_space or is_comment; + if (!is_space) { + exit(1); + } + exit(0); + } else { + exit(1); + } + } } const FileStartToken = enum{