diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index 89d2fa2..c802285 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -4358,11 +4358,13 @@ pub const IntrinsicId = enum { @"asm", //this is processed separately as it need special parsing cast, enum_to_int, + fields, @"export", @"error", int_to_pointer, import, min, + name, size, sign_extend, syscall, @@ -4506,42 +4508,6 @@ pub const Builder = struct { } } - fn processArrayLiteral(builder: *Builder, unit: *Unit, context: *const Context, constant_array_index: V.Comptime.ConstantArray.Index, token: Token.Index) !*Debug.Declaration.Global { - if (unit.global_array_constants.get(constant_array_index)) |global| { - return global; - } else { - const token_debug_info = builder.getTokenDebugInfo(unit, token); - const name = try join_name(context, "_anon_arr_", unit.global_array_constants.length, 10); - const identifier = try unit.processIdentifier(context, name); - const constant_array = unit.constant_arrays.get(constant_array_index); - - const global_declaration_index = try unit.global_declarations.append(context.allocator, .{ - .declaration = .{ - .scope = builder.current_scope, - .name = identifier, - .type = constant_array.type, - .line = token_debug_info.line, - .column = token_debug_info.column, - .mutability = .@"const", - .kind = .global, - }, - .initial_value = .{ - .constant_array = constant_array_index, - }, - .type_node_index = .null, - .attributes = Debug.Declaration.Global.Attributes.initMany(&.{ - .@"export", - }), - }); - const global_declaration = unit.global_declarations.get(global_declaration_index); - try unit.data_to_emit.append(context.allocator, global_declaration); - - try unit.global_array_constants.put_no_clobber(context.my_allocator, constant_array_index, global_declaration); - - return global_declaration; - } - } - fn processStringLiteralFromToken(builder: *Builder, unit: *Unit, context: *const Context, token_index: Token.Index) !*Debug.Declaration.Global { const string = try unit.fixupStringLiteral(context, token_index); const token_debug_info = builder.getTokenDebugInfo(unit, token_index); @@ -4887,10 +4853,89 @@ pub const Builder = struct { .type = .noreturn, }; }, + .fields => { + assert(argument_node_list.len == 1); + const container_type_index = try builder.resolveType(unit, context, argument_node_list[0], &.{}); + const fields = try builder.get_fields_array(unit, context, container_type_index, unit.getNode(argument_node_list[0]).token); + return .{ + .value = .{ + .@"comptime" = .{ + .global = fields, + }, + }, + .type = try unit.getPointerType(context, .{ + .type = fields.declaration.type, + .termination = .none, + .mutability = .@"const", + .many = false, + .nullable = false, + }), + }; + }, else => |t| @panic(@tagName(t)), } } + fn get_fields_array(builder: *Builder, unit: *Unit, context: *const Context, container_type_index: Type.Index, token: Token.Index) !*Debug.Declaration.Global{ + if (unit.fields_array.get(container_type_index)) |result| return result else { + const container_type = unit.types.get(container_type_index); + + switch (container_type.*) { + .integer => |*integer| switch (integer.kind) { + .@"enum" => |*enum_type| { + const enum_count = enum_type.fields.length; + const array_type = try unit.getArrayType(context, .{ + .type = container_type_index, + .count = enum_count, + .termination = .none, + }); + var fields = try UnpinnedArray(V.Comptime).initialize_with_capacity(context.my_allocator, enum_count); + for (enum_type.fields.slice()) |enum_field_index| { + fields.append_with_capacity(V.Comptime{ + .enum_value = enum_field_index, + }); + } + const constant_array = try unit.constant_arrays.append(context.my_allocator, .{ + .values = fields.slice(), + .type = array_type, + }); + + const token_debug_info = builder.getTokenDebugInfo(unit, token); + const name = try join_name(context, "_field_array_", unit.fields_array.length, 10); + const identifier = try unit.processIdentifier(context, name); + + const global_declaration_index = try unit.global_declarations.append(context.my_allocator, .{ + .declaration = .{ + .scope = builder.current_scope, + .name = identifier, + .type = array_type, + .line = token_debug_info.line, + .column = token_debug_info.column, + .mutability = .@"const", + .kind = .global, + }, + .initial_value = .{ + .constant_array = constant_array, + }, + .type_node_index = .null, + .attributes = Debug.Declaration.Global.Attributes.initMany(&.{ + .@"export", + }), + }); + const global_declaration = unit.global_declarations.get(global_declaration_index); + try unit.data_to_emit.append(context.my_allocator, global_declaration); + + try unit.fields_array.put_no_clobber(context.my_allocator, container_type_index, global_declaration); + + return global_declaration; + }, + else => |t| @panic(@tagName(t)), + }, + else => |t| @panic(@tagName(t)), + } + } + } + fn resolveCast(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index, value: V) !Instruction.Cast.Id { _ = builder; // autofix _ = context; // autofix @@ -13630,24 +13675,24 @@ pub const Builder = struct { }, else => blk: { const for_loop_value = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, last_element_node_index, .right); - try slices.append(context.my_allocator, for_loop_value); + + const name = try join_name(context, "__anon_i_", unit.anon_i, 10); + unit.anon_i += 1; + const emit = true; + const stack_slot = try builder.emitLocalVariableDeclaration(unit, context, last_element_payload.token, .@"var", Type.usize, .{ + .value = .{ + .@"comptime" = .{ + .constant_int = .{ + .value = 0, + }, + }, + }, + .type = Type.usize, + }, emit, name); switch (unit.types.get(for_loop_value.type).*) { - .slice => |slice| { - _ = slice; // autofix - const name = try join_name(context, "__anon_i_", unit.anon_i, 10); - unit.anon_i += 1; - const emit = true; - const stack_slot = try builder.emitLocalVariableDeclaration(unit, context, last_element_payload.token, .@"var", Type.usize, .{ - .value = .{ - .@"comptime" = .{ - .constant_int = .{ - .value = 0, - }, - }, - }, - .type = Type.usize, - }, emit, name); + .slice => { + try slices.append(context.my_allocator, for_loop_value); const len_extract_value = try unit.instructions.append(context.my_allocator, .{ .extract_value = .{ @@ -13667,6 +13712,59 @@ pub const Builder = struct { }, }; }, + .pointer => |pointer| switch (unit.types.get(pointer.type).*){ + .array => |array| { + const slice_type = try unit.getSliceType(context, .{ + .child_pointer_type = try unit.getPointerType(context, .{ + .type = array.type, + .termination = pointer.termination, + .mutability = pointer.mutability, + .many = true, + .nullable = pointer.nullable, + }), + .child_type = array.type, + .termination = pointer.termination, + .mutability = pointer.mutability, + .nullable = pointer.nullable, + }); + const slice = try unit.constant_slices.append(context.my_allocator, .{ + .array = switch (for_loop_value.value) { + .@"comptime" => |ct| switch (ct) { + .global => |global| global, + else => |t| @panic(@tagName(t)), + }, + else => |t| @panic(@tagName(t)), + }, + .start = 0, + .end = array.count, + .type = slice_type, + }); + const slice_value = V{ + .value = .{ + .@"comptime" = .{ + .constant_slice = slice, + }, + }, + .type = slice_type, + }; + try slices.append(context.my_allocator, slice_value); + break :blk .{ + .stack_slot = stack_slot, + .end = .{ + .value = .{ + .@"comptime" = .{ + .constant_int = .{ + .value = array.count, + }, + }, + }, + .type = Type.usize, + }, + }; + // TODO: fix this + }, + else => |t| @panic(@tagName(t)), + }, else => |t| @panic(@tagName(t)), } }, @@ -15916,7 +16014,7 @@ pub const Unit = struct { integers: MyHashMap(Type.Integer, Type.Index) = .{}, error_unions: MyHashMap(Type.Error.Union.Descriptor, Type.Index) = .{}, two_structs: MyHashMap([2]Type.Index, Type.Index) = .{}, - global_array_constants: MyHashMap(V.Comptime.ConstantArray.Index, *Debug.Declaration.Global) = .{}, + fields_array: MyHashMap(Type.Index, *Debug.Declaration.Global) = .{}, error_count: u32 = 0, code_to_emit: MyHashMap(Function.Definition.Index, *Debug.Declaration.Global) = .{}, diff --git a/bootstrap/backend/llvm.zig b/bootstrap/backend/llvm.zig index ab54423..50777e8 100644 --- a/bootstrap/backend/llvm.zig +++ b/bootstrap/backend/llvm.zig @@ -2016,7 +2016,7 @@ pub const LLVM = struct { .file => { unreachable; }, - .file_container => { + .file_container, .struct_type => { if (llvm.scope_map.get(sema_scope)) |scope| { if (true) unreachable; return scope; @@ -2087,6 +2087,16 @@ pub const LLVM = struct { }, .constant_slice => |constant_slice_index| try llvm.getConstantSlice(unit, context, constant_slice_index), .constant_struct => |constant_struct_index| try llvm.getConstantStruct(unit, context, constant_struct_index), + .enum_value => |enum_field_index| b: { + const integer_type = unit.types.get(sema_array_type.type).integer; + const signed = switch (integer_type.signedness) { + .signed => true, + .unsigned => false, + }; + assert(!signed); + const constant_int = llvm.context.getConstantInt(integer_type.bit_count, unit.enum_fields.get(enum_field_index).value, signed) orelse unreachable; + break :b constant_int.toConstant(); + }, else => |t| @panic(@tagName(t)), }; list.append_with_capacity(value); diff --git a/src/main.nat b/src/main.nat index 65ecc93..e390086 100644 --- a/src/main.nat +++ b/src/main.nat @@ -12,6 +12,10 @@ const ArgumentProcessingError = error{ const Token = struct { const Id = enum(u8) { + invalid, + keyword_unsigned_integer, + keyword_signed_integer, + identifier, }; }; @@ -42,6 +46,7 @@ const lex = fn (arena: &Arena, bytes: []const u8) *!void { while (index < length) { const start_index = index; const start_character = bytes[index]; + var token_id = Token.Id.invalid; switch (start_character) { 'a'...'z', 'A'...'Z', '_' => { @@ -54,6 +59,23 @@ const lex = fn (arena: &Arena, bytes: []const u8) *!void { break; } + + if (start_character == 'u' or start_character == 's' and bytes[start_index + 1] >= '0' and bytes[start_index + 1] <= '9') { + var index_integer = start_index + 1; + while (bytes[index_integer] >= '0' and bytes[index_integer] <= '9') { + index_integer += 1; + } + + if (index_integer == index) { + token_id = switch (start_character) { + 'u' => .keyword_unsigned_integer, + 's' => .keyword_signed_integer, + else => unreachable, + }; + } else { + //unreachable; + } + } }, else => index += 1, } diff --git a/test/standalone/enum_metaprogramming/main.nat b/test/standalone/enum_metaprogramming/main.nat new file mode 100644 index 0000000..001ef36 --- /dev/null +++ b/test/standalone/enum_metaprogramming/main.nat @@ -0,0 +1,24 @@ +const std = #import("std"); +const print = std.print; +const print_usize = std.print_usize; +const expect = std.testing.expect; + +const Enum = enum(u32) { + a, b, c, +}; + +const main = fn () *!void { + var result: u32 = 0; + for (#fields(Enum)) |e| { + //print(#name(e)); + //print(": "); + const value: u32 = #cast(e); + print_usize(value); + print("\n"); + result += value; + } + + //try expect(#fields(Enum).length == 3); + + try expect(result == 3); +}