diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index f4c7dce..c98592a 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -245,24 +245,33 @@ pub const Type = union(enum) { array: Array, optional: Optional, - const Optional = struct { + pub const Optional = struct { element_type: Type.Index, }; + pub const Termination = enum { + none, + null, + zero, + }; + pub const Array = struct { element_type: Type.Index, - element_count: u32, + element_count: usize, + termination: Termination, }; pub const Slice = struct { element_type: Type.Index, @"const": bool, + termination: Termination, }; pub const Pointer = struct { element_type: Type.Index, many: bool, @"const": bool, + termination: Termination, }; pub const List = BlockList(@This()); @@ -416,6 +425,7 @@ pub const extra_common_type_data = blk: { .many = true, .@"const" = true, .element_type = Type.u8, + .termination = .null, }, }; @@ -765,6 +775,7 @@ pub const Value = union(enum) { branch: Branch.Index, cast: Cast.Index, container_initialization: ContainerInitialization.Index, + array_initialization: ContainerInitialization.Index, field_access: FieldAccess.Index, slice_access: Slice.Access.Index, indexed_access: IndexedAccess.Index, @@ -822,7 +833,9 @@ pub const Value = union(enum) { .binary_operation => |binary_operation| module.values.binary_operations.get(binary_operation).type, .bool => Type.boolean, .declaration => Type.void, - .container_initialization => |container_initialization| module.values.container_initializations.get(container_initialization).type, + .container_initialization, + .array_initialization, + => |initialization| module.values.container_initializations.get(initialization).type, .syscall => Type.usize, .unary_operation => |unary_operation_index| module.values.unary_operations.get(unary_operation_index).type, .pointer_null_literal => semantic_analyzer.optional_pointer_to_any_type, @@ -887,7 +900,6 @@ pub const Module = struct { types: struct { array: BlockList(Type) = .{}, enums: BlockList(Enum) = .{}, - arrays: BlockList(Type.Array) = .{}, structs: BlockList(Struct) = .{}, container_fields: BlockList(ContainerField) = .{}, enum_fields: BlockList(Enum.Field) = .{}, @@ -1188,6 +1200,7 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) ! .element_type = Type.any, .many = false, .@"const" = true, + .termination = .none, }, }); semantic_analyzer.optional_pointer_to_any_type = try module.types.array.append(compilation.base_allocator, .{ @@ -1360,7 +1373,7 @@ pub fn log(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger } pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, return_address: ?usize) noreturn { - const print_stack_trace = true; + const print_stack_trace = false; switch (print_stack_trace) { true => @call(.always_inline, std.builtin.default_panic, .{ message, stack_trace, return_address }), false => { diff --git a/bootstrap/backend/c_transpiler.zig b/bootstrap/backend/c_transpiler.zig index 518a952..db06637 100644 --- a/bootstrap/backend/c_transpiler.zig +++ b/bootstrap/backend/c_transpiler.zig @@ -6,6 +6,8 @@ const equal = std.mem.eql; const Compilation = @import("../Compilation.zig"); const logln = Compilation.logln; const Module = Compilation.Module; +const Type = Compilation.Type; +const Value = Compilation.Value; const data_structures = @import("../data_structures.zig"); const ArrayList = data_structures.ArrayList; const AutoArrayHashMap = data_structures.AutoArrayHashMap; @@ -21,6 +23,37 @@ pub const Logger = enum { const margin_width = 4; +const TypeSet = struct { + map: AutoArrayHashMap(Type.Index, TypeValue) = .{}, + + const TypeValue = struct { + underscore: []const u8, + space: []const u8, + }; + + fn get(type_set: *const TypeSet, type_index: Type.Index, character: u8) ?[]const u8 { + if (type_set.map.get(type_index)) |value| { + const result = switch (character) { + '_' => value.underscore, + ' ' => value.space, + else => unreachable, + }; + return result; + } else { + return null; + } + } + + fn put(type_set: *TypeSet, allocator: Allocator, type_index: Type.Index, value: TypeValue) !void { + try type_set.map.putNoClobber(allocator, type_index, value); + } + + fn getOrPutValue(type_set: *TypeSet, allocator: Allocator, type_index: Type.Index, value: TypeValue) !TypeValue { + const gop = try type_set.map.getOrPutValue(allocator, type_index, value); + return gop.value_ptr.*; + } +}; + pub const TranslationUnit = struct { string_literals: ArrayList(u8) = .{}, primitive_type_declarations: ArrayList(u8) = .{}, @@ -30,12 +63,13 @@ pub const TranslationUnit = struct { global_variable_declarations: ArrayList(u8) = .{}, function_definitions: ArrayList(u8) = .{}, syscall_bitset: SyscallBitset = SyscallBitset.initEmpty(), - struct_type_set: AutoArrayHashMap(Compilation.Type.Index, []const u8) = .{}, - optional_type_set: AutoArrayHashMap(Compilation.Type.Index, []const u8) = .{}, function_set: AutoArrayHashMap(Compilation.Function.Index, []const u8) = .{}, - slice_type_set: AutoArrayHashMap(Compilation.Type.Index, []const u8) = .{}, - array_type_set: AutoArrayHashMap(Compilation.Type.Index, []const u8) = .{}, - enum_type_set: AutoArrayHashMap(Compilation.Type.Index, []const u8) = .{}, + struct_type_set: TypeSet = .{}, + optional_type_set: TypeSet = .{}, + slice_type_set: TypeSet = .{}, + array_type_set: TypeSet = .{}, + enum_type_set: TypeSet = .{}, + pointer_type_set: TypeSet = .{}, declaration_set: AutoArrayHashMap(Compilation.Declaration.Index, []const u8) = .{}, const SyscallBitset = std.StaticBitSet(7); @@ -98,29 +132,37 @@ pub const TranslationUnit = struct { } } - fn writeDeclaration(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, declaration_index: Compilation.Declaration.Index, indentation: usize) !void { + fn writeDeclaration(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, declaration_index: Compilation.Declaration.Index, indentation: usize, separation_character: u8) !void { const declaration = module.values.declarations.get(declaration_index); const mangle = false; const name = try unit.renderDeclarationName(module, allocator, declaration_index, mangle); + // if (equal(u8, name, "pointer")) { + // @breakpoint(); + // } if (declaration.mutability == .@"const") { switch (module.types.array.get(declaration.type).*) { .optional => |optional| switch (module.types.array.get(optional.element_type).*) { .pointer => {}, - else => try list.appendSlice(allocator, "const "), + else => { + try list.appendSlice(allocator, "const "); + }, }, .pointer => {}, .integer, .@"struct", .slice, .bool, - => try list.appendSlice(allocator, "const "), + .array, + => { + try list.appendSlice(allocator, "const "); + }, else => |t| @panic(@tagName(t)), //else => try list.appendSlice(allocator, "const "), } } - try unit.writeType(module, list, allocator, declaration.type); + try unit.writeType(module, list, allocator, declaration.type, separation_character); try list.append(allocator, ' '); @@ -128,13 +170,13 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, " = "); - try unit.writeValue(module, list, allocator, Compilation.Type.Index.invalid, indentation, .{ + try unit.writeValue(module, list, allocator, Type.Index.invalid, indentation, .{ .value_index = declaration.init_value, .type_index = declaration.type, }); } - fn writeAssignment(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, assignment_index: Compilation.Assignment.Index, function_return_type: Compilation.Type.Index, indentation: usize) !void { + fn writeAssignment(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, assignment_index: Compilation.Assignment.Index, function_return_type: Type.Index, indentation: usize) !void { const assignment = module.values.assignments.get(assignment_index); const left_type = module.values.array.get(assignment.source).getType(module); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ @@ -149,11 +191,11 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, "= "); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = assignment.source, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); } - fn writeBlock(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, block_index: Compilation.Block.Index, function_return_type: Compilation.Type.Index, old_indentation: usize) !void { + fn writeBlock(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, block_index: Compilation.Block.Index, function_return_type: Type.Index, old_indentation: usize) !void { try list.appendSlice(allocator, "{\n"); const block = module.values.blocks.get(block_index); @@ -165,7 +207,7 @@ pub const TranslationUnit = struct { const statement = module.values.array.get(statement_index); switch (statement.*) { .declaration => |declaration_index| { - try unit.writeDeclaration(module, list, allocator, declaration_index, indentation); + try unit.writeDeclaration(module, list, allocator, declaration_index, indentation, ' '); try list.append(allocator, ';'); }, .assign => |assignment_index| { @@ -186,7 +228,7 @@ pub const TranslationUnit = struct { }), else => { try list.append(allocator, '('); - try unit.writeType(module, list, allocator, function_return_type); + try unit.writeType(module, list, allocator, function_return_type, '_'); try list.appendSlice(allocator, ") {\n"); try list.appendNTimes(allocator, ' ', indentation * margin_width); @@ -227,7 +269,7 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, "if ("); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = branch.expression, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, ") "); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ @@ -262,14 +304,14 @@ pub const TranslationUnit = struct { if (!loop.pre.invalid) { try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = loop.pre, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); } try list.appendSlice(allocator, "; "); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = loop.condition, - .type_index = Compilation.Type.boolean, + .type_index = Type.boolean, }); try list.appendSlice(allocator, "; "); @@ -277,7 +319,7 @@ pub const TranslationUnit = struct { if (!loop.post.invalid) { try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = loop.post, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); } @@ -285,7 +327,7 @@ pub const TranslationUnit = struct { try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = loop.body, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); }, .block => |new_block_index| { @@ -306,7 +348,7 @@ pub const TranslationUnit = struct { header, }; - fn renderTypeName(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 { + fn renderTypeName(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Type.Index) ![]const u8 { const declaration_index = module.map.types.get(type_index).?; const mangle = true; const result = try unit.renderDeclarationName(module, allocator, declaration_index, mangle); @@ -371,7 +413,7 @@ pub const TranslationUnit = struct { .type, => {}, .@"struct" => { - try unit.writeDeclaration(module, &unit.global_variable_declarations, allocator, declaration_index, 0); + try unit.writeDeclaration(module, &unit.global_variable_declarations, allocator, declaration_index, 0, '_'); try unit.global_variable_declarations.append(allocator, ';'); try unit.global_variable_declarations.appendNTimes(allocator, '\n', 2); }, @@ -391,7 +433,7 @@ pub const TranslationUnit = struct { .naked => try list.appendSlice(allocator, "[[gnu::naked]] "), } - try unit.writeType(module, list, allocator, function_prototype.return_type); + try unit.writeType(module, list, allocator, function_prototype.return_type, ' '); try list.append(allocator, ' '); @@ -402,7 +444,7 @@ pub const TranslationUnit = struct { if (function_prototype.arguments) |function_arguments| { for (function_arguments) |argument_index| { const arg_declaration = module.values.declarations.get(argument_index); - try unit.writeType(module, list, allocator, arg_declaration.type); + try unit.writeType(module, list, allocator, arg_declaration.type, ' '); try list.append(allocator, ' '); const arg_name = module.getName(arg_declaration.name).?; try list.appendSlice(allocator, arg_name); @@ -412,7 +454,7 @@ pub const TranslationUnit = struct { _ = list.pop(); } - try list.appendSlice(allocator, ")"); + try list.append(allocator, ')'); } fn writeFunctionHeader(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function_index: Compilation.Function.Index) ![]const u8 { @@ -425,7 +467,7 @@ pub const TranslationUnit = struct { return name; } - fn writeType(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, type_index: Compilation.Type.Index) anyerror!void { + fn writeType(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, type_index: Type.Index, separation_character: u8) anyerror!void { const sema_type = module.types.array.get(type_index); switch (sema_type.*) { @@ -439,46 +481,36 @@ pub const TranslationUnit = struct { }); try list.writer(allocator).print("{}", .{integer.bit_count}); }, - .pointer => |pointer| { - switch (module.types.array.get(pointer.element_type).*) { - .function => { - @panic("This should be unreachable"); - }, - else => { - if (pointer.@"const") { - try list.appendSlice(allocator, "const "); - } - try unit.writeType(module, list, allocator, pointer.element_type); - try list.append(allocator, '*'); - }, - } + .pointer => { + const name = try unit.cachePointerType(module, allocator, type_index, separation_character); + try list.appendSlice(allocator, name); }, .@"struct" => { - const name = try unit.cacheStructType(module, allocator, type_index); + const name = try unit.cacheStructType(module, allocator, type_index, separation_character); try list.appendSlice(allocator, name); }, .optional => { - const name = try unit.cacheOptionalType(module, allocator, type_index); + const name = try unit.cacheOptionalType(module, allocator, type_index, separation_character); try list.appendSlice(allocator, name); }, .slice => { - const name = try unit.cacheSliceType(module, allocator, type_index); + const name = try unit.cacheSliceType(module, allocator, type_index, separation_character); try list.appendSlice(allocator, name); }, .array => { - const name = try unit.cacheArrayType(module, allocator, type_index); + const name = try unit.cacheArrayType(module, allocator, type_index, separation_character); try list.appendSlice(allocator, name); }, .any => @panic("Internal compiler error: 'any' made it to the backend"), .@"enum" => { - const name = try unit.cacheEnumType(module, allocator, type_index); + const name = try unit.cacheEnumType(module, allocator, type_index, separation_character); try list.appendSlice(allocator, name); }, else => |t| @panic(@tagName(t)), } } - fn writeCDeclaration(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, name: []const u8, type_index: Compilation.Type.Index) !void { + fn writeCDeclaration(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, name: []const u8, type_index: Type.Index, separation_character: u8) !void { const declaration_type = module.types.array.get(type_index); switch (declaration_type.*) { .pointer => |pointer| { @@ -490,7 +522,7 @@ pub const TranslationUnit = struct { else => {}, } - try unit.writeType(module, list, allocator, type_index); + try unit.writeType(module, list, allocator, type_index, separation_character); try list.append(allocator, ' '); try list.appendSlice(allocator, name); } @@ -533,9 +565,9 @@ pub const TranslationUnit = struct { try list.writer(allocator).print("$0x{x}", .{number_literal}); }, .value_index => |value_index| { - try unit.writeValue(module, list, allocator, Compilation.Type.Index.invalid, indentation + 1, .{ + try unit.writeValue(module, list, allocator, Type.Index.invalid, indentation + 1, .{ .value_index = value_index, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); }, } @@ -556,15 +588,16 @@ pub const TranslationUnit = struct { try list.append(allocator, ')'); } - fn cacheStructType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 { + fn cacheStructType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Type.Index, separation_character: u8) ![]const u8 { const t = module.types.array.get(type_index); assert(t.* == .@"struct"); - if (unit.struct_type_set.getIndex(type_index)) |index| { - return unit.struct_type_set.values()[index]; - } else { + const result = if (unit.struct_type_set.get(type_index, separation_character)) |r| r else blk: { const type_name = try unit.renderTypeName(module, allocator, type_index); logln(.c, .g, "Registering struct {s}: #{}", .{ type_name, type_index.uniqueInteger() }); - try unit.struct_type_set.putNoClobber(allocator, type_index, type_name); + try unit.struct_type_set.put(allocator, type_index, .{ + .underscore = type_name, + .space = type_name, + }); try unit.forwardDeclareContainerType(allocator, .@"struct", type_name); @@ -584,13 +617,13 @@ pub const TranslationUnit = struct { switch (struct_type.backing_type.invalid) { false => { - try unit.writeType(module, &list, allocator, struct_type.backing_type); + try unit.writeType(module, &list, allocator, struct_type.backing_type, '_'); try list.append(allocator, ' '); try list.appendSlice(allocator, struct_field_name); try list.appendSlice(allocator, " : "); try list.writer(allocator).print("{}", .{module.types.array.get(struct_field.type).getBitSize()}); }, - true => try unit.writeCDeclaration(module, &list, allocator, struct_field_name, struct_field.type), + true => try unit.writeCDeclaration(module, &list, allocator, struct_field_name, struct_field.type, '_'), } try list.appendSlice(allocator, ";\n"); @@ -603,8 +636,10 @@ pub const TranslationUnit = struct { try unit.type_declarations.appendSlice(allocator, list.items); } - return type_name; - } + break :blk type_name; + }; + + return result; } fn forwardDeclareContainerType(unit: *TranslationUnit, allocator: Allocator, container_type: Compilation.ContainerType, type_name: []const u8) !void { @@ -617,13 +652,14 @@ pub const TranslationUnit = struct { try unit.type_forward_declarations.appendSlice(allocator, ";\n"); } - fn cacheEnumType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 { - if (unit.array_type_set.getIndex(type_index)) |index| { - return unit.array_type_set.values()[index]; - } else { + fn cacheEnumType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Type.Index, separation_character: u8) ![]const u8 { + const result = if (unit.array_type_set.get(type_index, separation_character)) |r| r else blk: { const type_name = try unit.renderTypeName(module, allocator, type_index); logln(.c, .g, "Registering enum {s}: #{}", .{ type_name, type_index.uniqueInteger() }); - try unit.array_type_set.putNoClobber(allocator, type_index, type_name); + try unit.array_type_set.put(allocator, type_index, .{ + .underscore = type_name, + .space = type_name, + }); try unit.forwardDeclareContainerType(allocator, .@"enum", type_name); @@ -648,9 +684,9 @@ pub const TranslationUnit = struct { if (!enum_field.value.invalid) { try list.appendSlice(allocator, " = "); - try unit.writeValue(module, &list, allocator, Compilation.Type.Index.invalid, 0, .{ + try unit.writeValue(module, &list, allocator, Type.Index.invalid, 0, .{ .value_index = enum_field.value, - .type_index = Compilation.Type.usize, + .type_index = Type.usize, }); } @@ -663,33 +699,34 @@ pub const TranslationUnit = struct { try unit.type_declarations.appendSlice(allocator, list.items); - return type_name; - } + break :blk type_name; + }; + + return result; } - fn cacheOptionalType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 { + fn cacheOptionalType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Type.Index, separation_character: u8) ![]const u8 { const optional_type = module.types.array.get(type_index); assert(optional_type.* == .optional); const optional = optional_type.optional; - if (unit.optional_type_set.getIndex(optional.element_type)) |index| { - return unit.optional_type_set.values()[index]; - } else { + const result = if (unit.optional_type_set.get(optional.element_type, separation_character)) |r| r else { const optional_element_type = module.types.array.get(optional.element_type); switch (optional_element_type.*) { .pointer => { - var type_name = ArrayList(u8){}; - try unit.writeType(module, &type_name, allocator, optional.element_type); - try unit.optional_type_set.putNoClobber(allocator, optional.element_type, type_name.items); - return type_name.items; + const name = try unit.cachePointerType(module, allocator, optional.element_type, separation_character); + return name; }, else => { var type_name = ArrayList(u8){}; try type_name.appendSlice(allocator, "Optional_"); - try unit.writeType(module, &type_name, allocator, optional.element_type); + try unit.writeType(module, &type_name, allocator, optional.element_type, '_'); logln(.c, .g, "Registering optional {s}: #{}", .{ type_name.items, type_index.uniqueInteger() }); - try unit.optional_type_set.putNoClobber(allocator, optional.element_type, type_name.items); + try unit.optional_type_set.put(allocator, optional.element_type, .{ + .underscore = type_name.items, + .space = type_name.items, + }); try unit.forwardDeclareContainerType(allocator, .@"struct", type_name.items); @@ -700,11 +737,11 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, " {\n"); try list.appendNTimes(allocator, ' ', margin_width); - try unit.writeCDeclaration(module, &list, allocator, "value", optional.element_type); + try unit.writeCDeclaration(module, &list, allocator, "value", optional.element_type, separation_character); try list.appendSlice(allocator, ";\n"); try list.appendNTimes(allocator, ' ', margin_width); - try unit.writeCDeclaration(module, &list, allocator, "is_null", Compilation.Type.boolean); + try unit.writeCDeclaration(module, &list, allocator, "is_null", Type.boolean, separation_character); try list.appendSlice(allocator, ";\n"); try list.appendSlice(allocator, "} "); @@ -716,20 +753,23 @@ pub const TranslationUnit = struct { return type_name.items; }, } - } + }; + + return result; } - fn cacheSliceType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 { + fn cacheSliceType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Type.Index, separation_character: u8) ![]const u8 { const slice = module.types.array.get(type_index).slice; - if (unit.slice_type_set.getIndex(slice.element_type)) |index| { - return unit.slice_type_set.values()[index]; - } else { + const result = if (unit.slice_type_set.get(slice.element_type, separation_character)) |r| r else blk: { var type_name = ArrayList(u8){}; try type_name.appendSlice(allocator, "Slice_"); - try unit.writeType(module, &type_name, allocator, slice.element_type); + try unit.writeType(module, &type_name, allocator, slice.element_type, separation_character); logln(.c, .g, "Registering slice {s}: #{}", .{ type_name.items, type_index.uniqueInteger() }); - try unit.slice_type_set.putNoClobber(allocator, slice.element_type, type_name.items); + try unit.slice_type_set.put(allocator, slice.element_type, .{ + .underscore = type_name.items, + .space = type_name.items, + }); try unit.forwardDeclareContainerType(allocator, .@"struct", type_name.items); @@ -740,7 +780,7 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, " {\n"); try list.appendNTimes(allocator, ' ', margin_width); - try unit.writeType(module, &list, allocator, slice.element_type); + try unit.writeType(module, &list, allocator, slice.element_type, '_'); try list.appendSlice(allocator, "* ptr;\n"); try list.appendNTimes(allocator, ' ', margin_width); @@ -752,22 +792,72 @@ pub const TranslationUnit = struct { try unit.type_declarations.appendSlice(allocator, list.items); - return type_name.items; - } + break :blk type_name.items; + }; + + return result; } - fn cacheArrayType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 { + fn cachePointerType(unit: *TranslationUnit, module: *Module, allocator: Allocator, pointer_type_index: Type.Index, separation_character: u8) ![]const u8 { + const result = if (unit.pointer_type_set.get(pointer_type_index, separation_character)) |r| r else blk: { + var underscore_type_name = ArrayList(u8){}; + var space_type_name = ArrayList(u8){}; + const pointer_type = module.types.array.get(pointer_type_index).pointer; + try underscore_type_name.appendSlice(allocator, "Pointer_"); + if (pointer_type.@"const") { + try underscore_type_name.appendSlice(allocator, "const_"); + } + if (pointer_type.many) { + try underscore_type_name.appendSlice(allocator, "many_"); + } + try unit.writeType(module, &underscore_type_name, allocator, pointer_type.element_type, '_'); + try unit.writeType(module, &space_type_name, allocator, pointer_type.element_type, ' '); + if (pointer_type.@"const") { + try space_type_name.appendSlice(allocator, " const"); + } + try space_type_name.append(allocator, '*'); + + const result = try unit.pointer_type_set.getOrPutValue(allocator, pointer_type_index, .{ + .underscore = underscore_type_name.items, + .space = space_type_name.items, + }); + + break :blk switch (separation_character) { + '_' => result.underscore, + ' ' => result.space, + else => unreachable, + }; + }; + + return result; + } + + fn cacheArrayType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Type.Index, separation_character: u8) ![]const u8 { const array = module.types.array.get(type_index).array; - if (unit.array_type_set.getIndex(array.element_type)) |index| { - return unit.array_type_set.values()[index]; - } else { + const result = if (unit.array_type_set.get(array.element_type, separation_character)) |r| r else blk: { var type_name = ArrayList(u8){}; try type_name.appendSlice(allocator, "Array_"); - try unit.writeType(module, &type_name, allocator, array.element_type); + try unit.writeType(module, &type_name, allocator, array.element_type, '_'); try type_name.writer(allocator).print("_{}", .{array.element_count}); + var terminated = false; + switch (array.termination) { + .none => {}, + .zero, + .null, + => { + terminated = true; + try type_name.append(allocator, '_'); + try type_name.writer(allocator).writeAll(@tagName(array.termination)); + try type_name.appendSlice(allocator, "_terminated"); + }, + } logln(.c, .g, "Registering array {s}: #{}", .{ type_name.items, type_index.uniqueInteger() }); - try unit.array_type_set.putNoClobber(allocator, array.element_type, type_name.items); + + try unit.array_type_set.put(allocator, array.element_type, .{ + .underscore = type_name.items, + .space = type_name.items, + }); try unit.forwardDeclareContainerType(allocator, .@"struct", type_name.items); @@ -778,10 +868,10 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, " {\n"); try list.appendNTimes(allocator, ' ', margin_width); - try unit.writeType(module, &list, allocator, array.element_type); - try list.appendSlice(allocator, " value\n"); + try unit.writeType(module, &list, allocator, array.element_type, ' '); + try list.appendSlice(allocator, " value"); - try list.writer(allocator).print("[{}];\n", .{array.element_count}); + try list.writer(allocator).print("[{}];\n", .{array.element_count + @intFromBool(terminated)}); try list.appendSlice(allocator, "} "); try list.appendSlice(allocator, type_name.items); @@ -789,11 +879,13 @@ pub const TranslationUnit = struct { try unit.type_declarations.appendSlice(allocator, list.items); - return type_name.items; - } + break :blk type_name.items; + }; + + return result; } - fn writeSyscall(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, syscall_index: Compilation.Syscall.Index, function_return_type: Compilation.Type.Index, indentation: usize) !void { + fn writeSyscall(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, syscall_index: Compilation.Syscall.Index, function_return_type: Type.Index, indentation: usize) !void { const syscall = module.values.syscalls.get(syscall_index); const arguments = syscall.getArguments(); @@ -865,7 +957,7 @@ pub const TranslationUnit = struct { for (arguments) |argument_index| { try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = argument_index, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, ", "); } @@ -879,7 +971,7 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, "__builtin_unreachable()"); } - fn writeCall(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, call_index: Compilation.Call.Index, function_return_type: Compilation.Type.Index, indentation: usize) !void { + fn writeCall(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, call_index: Compilation.Call.Index, function_return_type: Type.Index, indentation: usize) !void { const call = module.values.calls.get(call_index); const call_value = module.values.array.get(call.value); switch (call_value.*) { @@ -922,7 +1014,7 @@ pub const TranslationUnit = struct { for (argument_list.array.items) |argument_index| { try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = argument_index, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, ", "); } @@ -936,19 +1028,19 @@ pub const TranslationUnit = struct { } const ValueArguments = struct { - value_index: Compilation.Value.Index, - type_index: Compilation.Type.Index, + value_index: Value.Index, + type_index: Type.Index, }; - fn writeValue(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function_return_type: Compilation.Type.Index, indentation: usize, arguments: ValueArguments) anyerror!void { + fn writeValue(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function_return_type: Type.Index, indentation: usize, arguments: ValueArguments) anyerror!void { const value_index = arguments.value_index; const type_index = arguments.type_index; _ = type_index; const value = module.values.array.get(value_index); - logln(.c, .g, "Generating C code for {s}", .{@tagName(value.*)}); + //logln(.c, .g, "Generating C code for {s}", .{@tagName(value.*)}); switch (value.*) { .declaration => |declaration_index| { - try unit.writeDeclaration(module, list, allocator, declaration_index, indentation); + try unit.writeDeclaration(module, list, allocator, declaration_index, indentation, '.'); }, .assign => |assignment_index| { try unit.writeAssignment(module, list, allocator, assignment_index, function_return_type, indentation); @@ -1002,7 +1094,7 @@ pub const TranslationUnit = struct { .cast => |cast_index| { const cast = module.values.casts.get(cast_index); try list.append(allocator, '('); - try unit.writeType(module, list, allocator, cast.type); + try unit.writeType(module, list, allocator, cast.type, ' '); try list.append(allocator, ')'); const cast_value = module.values.array.get(cast.value); const cast_value_type = module.types.array.get(cast_value.getType(module)); @@ -1013,7 +1105,7 @@ pub const TranslationUnit = struct { switch (struct_type.backing_type.invalid) { false => { try list.appendSlice(allocator, "*("); - try unit.writeType(module, list, allocator, struct_type.backing_type); + try unit.writeType(module, list, allocator, struct_type.backing_type, '_'); try list.appendSlice(allocator, "*)&("); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = cast.value, @@ -1026,12 +1118,12 @@ pub const TranslationUnit = struct { }, else => try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = cast.value, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }), } }, .string_literal => |string_literal_descriptor| { - try list.appendSlice(allocator, "(const u8*)"); + try list.appendSlice(allocator, "(u8 *)"); const string_literal = module.getName(string_literal_descriptor.hash) orelse unreachable; try list.append(allocator, '"'); try list.appendSlice(allocator, string_literal); @@ -1063,32 +1155,92 @@ pub const TranslationUnit = struct { }, .container_initialization => |container_initialization_index| { const container_initialization = module.values.container_initializations.get(container_initialization_index); + try list.append(allocator, '('); - try unit.writeType(module, list, allocator, container_initialization.type); + try unit.writeType(module, list, allocator, container_initialization.type, '_'); try list.appendSlice(allocator, ") {\n"); const container_type = module.types.array.get(container_initialization.type); - const container_fields = switch (container_type.*) { - .@"struct" => module.types.structs.get(container_type.@"struct").fields, + switch (container_type.*) { + .@"struct" => { + const container_fields = module.types.structs.get(container_type.@"struct").fields; + + for (container_initialization.field_initializations.items, container_fields.items) |field_initialization_index, container_field_index| { + try list.appendNTimes(allocator, ' ', (indentation + 1) * margin_width); + try list.append(allocator, '.'); + const container_field = module.types.container_fields.get(container_field_index); + const field_name = module.getName(container_field.name).?; + try list.appendSlice(allocator, field_name); + try list.appendSlice(allocator, " = "); + try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ + .value_index = field_initialization_index, + .type_index = container_field.type, + }); + try list.appendSlice(allocator, ",\n"); + } + + try list.appendNTimes(allocator, ' ', indentation * margin_width); + try list.append(allocator, '}'); + }, + .array => |array_type| { + try list.appendNTimes(allocator, ' ', (indentation + 1) * margin_width); + try list.appendSlice(allocator, ".value = {\n"); + + for (container_initialization.field_initializations.items, 0..) |field_initialization_index, array_index| { + try list.appendNTimes(allocator, ' ', (indentation + 2) * margin_width); + try list.writer(allocator).print("[{}] = ", .{array_index}); + + try unit.writeValue(module, list, allocator, function_return_type, indentation + 2, .{ + .value_index = field_initialization_index, + .type_index = Type.Index.invalid, + }); + + try list.appendSlice(allocator, " ,\n"); + } + + switch (array_type.termination) { + .none => {}, + .null, .zero => { + try list.appendNTimes(allocator, ' ', (indentation + 2) * margin_width); + const termination: []const u8 = switch (array_type.termination) { + .null => "nullptr", + .zero => "0", + else => unreachable, + }; + try list.writer(allocator).print("[{}] = {s},\n", .{ container_initialization.field_initializations.items.len, termination }); + }, + } + + try list.appendNTimes(allocator, ' ', (indentation + 1) * margin_width); + try list.appendSlice(allocator, "},\n"); + + try list.appendNTimes(allocator, ' ', indentation * margin_width); + try list.append(allocator, '}'); + }, else => |t| @panic(@tagName(t)), - }; - - for (container_initialization.field_initializations.items, container_fields.items) |field_initialization_index, container_field_index| { - try list.appendNTimes(allocator, ' ', (indentation + 1) * margin_width); - try list.append(allocator, '.'); - const container_field = module.types.container_fields.get(container_field_index); - const field_name = module.getName(container_field.name).?; - try list.appendSlice(allocator, field_name); - try list.appendSlice(allocator, " = "); - try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ - .value_index = field_initialization_index, - .type_index = container_field.type, - }); - try list.appendSlice(allocator, ",\n"); } + }, + .array_initialization => |array_initialization_index| { + const array_initialization = module.values.container_initializations.get(array_initialization_index); + try list.append(allocator, '('); + try unit.writeType(module, list, allocator, array_initialization.type, '_'); + try list.appendSlice(allocator, ") { "); - try list.appendNTimes(allocator, ' ', indentation * margin_width); - try list.append(allocator, '}'); + if (array_initialization.field_initializations.items.len > 0) { + for (array_initialization.field_initializations.items) |initialization_index| { + try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ + .value_index = initialization_index, + .type_index = module.values.array.get(initialization_index).getType(module), + }); + try list.appendSlice(allocator, ", "); + // const container_field = module.types.container_fields.get(initialization_index); + // const field_name = module.getName(container_field.name).?; + } + + _ = list.pop(); + } + _ = list.pop(); + list.appendSliceAssumeCapacity(" }"); }, .field_access => |field_access_index| { const field_access = module.values.field_accesses.get(field_access_index); @@ -1118,7 +1270,7 @@ pub const TranslationUnit = struct { .optional_null_literal => { assert(!arguments.type_index.invalid); try list.append(allocator, '('); - try unit.writeType(module, list, allocator, arguments.type_index); + try unit.writeType(module, list, allocator, arguments.type_index, '_'); try list.appendSlice(allocator, ") { .is_null = true }"); }, .slice => |slice_index| { @@ -1137,7 +1289,7 @@ pub const TranslationUnit = struct { }; try list.appendSlice(allocator, "(Slice_"); - try unit.writeType(module, list, allocator, sliceable_element_type); + try unit.writeType(module, list, allocator, sliceable_element_type, '_'); try list.appendSlice(allocator, ") {\n"); try list.appendNTimes(allocator, ' ', (indentation + 1) * margin_width); @@ -1153,7 +1305,7 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, ") + ("); try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ .value_index = slice.range.start, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, "),\n"); }, @@ -1166,7 +1318,7 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, ").ptr + ("); try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ .value_index = slice.range.start, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, "),\n"); }, @@ -1183,12 +1335,12 @@ pub const TranslationUnit = struct { try list.append(allocator, '('); try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ .value_index = slice.range.end, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, ") - ("); try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ .value_index = slice.range.start, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, ")\n"); }, @@ -1203,7 +1355,7 @@ pub const TranslationUnit = struct { false => { try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ .value_index = slice.range.end, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); }, true => { @@ -1212,7 +1364,7 @@ pub const TranslationUnit = struct { try list.append(allocator, '('); try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ .value_index = slice.sliceable, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, ").len"); }, @@ -1224,7 +1376,7 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, ") - ("); try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ .value_index = slice.range.start, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, ")\n"); }, @@ -1254,7 +1406,7 @@ pub const TranslationUnit = struct { try list.append(allocator, '('); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = optional_check.value, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.append(allocator, ')'); @@ -1314,7 +1466,7 @@ pub const TranslationUnit = struct { try list.appendSlice(allocator, ")["); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = indexed_access.index_expression, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.append(allocator, ']'); }, @@ -1331,13 +1483,13 @@ pub const TranslationUnit = struct { }), else => { try list.append(allocator, '('); - try unit.writeType(module, list, allocator, optional_cast.type); + try unit.writeType(module, list, allocator, optional_cast.type, '_'); try list.appendSlice(allocator, ") {\n"); try list.appendNTimes(allocator, ' ', indentation * margin_width); try list.appendSlice(allocator, ".value = "); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = optional_cast.value, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); try list.appendSlice(allocator, ",\n"); try list.appendNTimes(allocator, ' ', indentation * margin_width); @@ -1354,13 +1506,13 @@ pub const TranslationUnit = struct { .array_coerce_to_slice => |cast_index| { const array_coerce_to_slice = module.values.casts.get(cast_index); try list.append(allocator, '('); - try unit.writeType(module, list, allocator, array_coerce_to_slice.type); + try unit.writeType(module, list, allocator, array_coerce_to_slice.type, '_'); try list.appendSlice(allocator, ") {\n"); try list.appendNTimes(allocator, ' ', indentation * margin_width); try list.appendSlice(allocator, ".ptr = "); try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ .value_index = array_coerce_to_slice.value, - .type_index = Compilation.Type.Index.invalid, + .type_index = Type.Index.invalid, }); switch (module.values.array.get(array_coerce_to_slice.value).*) { .string_literal => {}, @@ -1384,7 +1536,7 @@ pub const TranslationUnit = struct { }, .enum_field => |enum_field_index| { const enum_field = module.types.enum_fields.get(enum_field_index); - try unit.writeType(module, list, allocator, enum_field.parent); + try unit.writeType(module, list, allocator, enum_field.parent, '_'); try list.append(allocator, '_'); const enum_field_name = module.getName(enum_field.name).?; try list.appendSlice(allocator, enum_field_name); diff --git a/bootstrap/frontend/semantic_analyzer.zig b/bootstrap/frontend/semantic_analyzer.zig index 072c670..a8b4dcf 100644 --- a/bootstrap/frontend/semantic_analyzer.zig +++ b/bootstrap/frontend/semantic_analyzer.zig @@ -25,6 +25,7 @@ const ScopeType = Compilation.ScopeType; const Slice = Compilation.Slice; const Struct = Compilation.Struct; const StringLiteral = Compilation.StringLiteral; +const Termination = Compilation.Type.Termination; const Type = Compilation.Type; const Value = Compilation.Value; @@ -79,7 +80,8 @@ const ExpectType = union(enum) { none, type_index: Type.Index, flexible_integer: FlexibleInteger, - addressable: Type.Index, + addressable: Addressable, + dereferenceable: Dereferenceable, pub const none = ExpectType{ .none = {}, @@ -96,6 +98,11 @@ const ExpectType = union(enum) { byte_count: u8, sign: ?bool = null, }; + + const Addressable = Type.Pointer; + const Dereferenceable = struct { + element_type: Type.Index, + }; }; pub var unreachable_index = Value.Index.invalid; @@ -1392,6 +1399,7 @@ const Analyzer = struct { break :blk declaration.type; }, .addressable => declaration.type, + .dereferenceable => unreachable, }, }, }); @@ -1767,6 +1775,7 @@ const Analyzer = struct { .element_type = slice_type_slice.element_type, .@"const" = slice_type_slice.@"const", .many = true, + .termination = slice_type_slice.termination, }); break :t pointer_type; }, @@ -1873,16 +1882,6 @@ const Analyzer = struct { .compare_less_or_equal, => try analyzer.processBinaryOperation(scope_index, expect_type, node_index), .expression_group => return try analyzer.resolveNode(value_index, scope_index, expect_type, node.left), //unreachable, - .container_literal => blk: { - const literal_type = try analyzer.resolveType(.{ - .scope_index = scope_index, - .node_index = node.left, - }); - const container_initialization = try analyzer.analyzeContainerLiteral(scope_index, literal_type, node.right); - break :blk .{ - .container_initialization = container_initialization, - }; - }, .struct_type => blk: { const left_node = analyzer.getScopeNode(scope_index, node.left); const nodes = analyzer.getScopeNodeList(scope_index, left_node); @@ -1892,13 +1891,6 @@ const Analyzer = struct { .type = struct_type, }; }, - .anonymous_container_literal => blk: { - assert(expect_type == .type_index); - const container_initialization = try analyzer.analyzeContainerLiteral(scope_index, expect_type.type_index, node.left); - break :blk .{ - .container_initialization = container_initialization, - }; - }, .boolean_not => blk: { const typecheck_result = try analyzer.typeCheck(expect_type, Type.boolean); assert(typecheck_result == .success); @@ -1936,36 +1928,35 @@ const Analyzer = struct { }; }, .address_of => blk: { - var many = false; - var is_const = false; - const new_expect_type = switch (expect_type) { + const many = false; + _ = many; + const addressable: ExpectType.Addressable = switch (expect_type) { // .none => expect_type, - .type_index => |type_index| ExpectType{ - .addressable = switch (analyzer.module.types.array.get(type_index).*) { - .pointer => |pointer| b: { - is_const = pointer.@"const"; - many = pointer.many; - break :b pointer.element_type; - }, - .slice => |slice| b: { - is_const = slice.@"const"; - many = true; - break :b slice.element_type; - }, - else => |t| @panic(@tagName(t)), + .type_index => |type_index| switch (analyzer.module.types.array.get(type_index).*) { + .pointer => |pointer| pointer, + .slice => |slice| .{ + .@"const" = slice.@"const", + .many = true, + .element_type = slice.element_type, + .termination = slice.termination, }, + else => |t| @panic(@tagName(t)), }, .flexible_integer => unreachable, else => unreachable, }; - logln(.sema, .address_of, "New expect type: {}", .{new_expect_type}); - const appointee_value_index = try analyzer.unresolvedAllocate(scope_index, new_expect_type, node.left); + const appointee_value_index = try analyzer.unresolvedAllocate(scope_index, ExpectType{ + .addressable = addressable, + }, node.left); + const unary_type_index: Type.Index = try analyzer.getPointerType(.{ .element_type = analyzer.module.values.array.get(appointee_value_index).getType(analyzer.module), - .many = many, - .@"const" = is_const, + .many = addressable.many, + .@"const" = addressable.@"const", + .termination = addressable.termination, }); + const unary_index = try analyzer.module.values.unary_operations.append(analyzer.allocator, .{ .id = .address_of, .value = appointee_value_index, @@ -1999,13 +1990,13 @@ const Analyzer = struct { .none => expect_type, .type_index => |type_index| switch (analyzer.module.types.array.get(type_index).*) { .pointer => unreachable, - else => ExpectType{ - .type_index = try analyzer.getPointerType(.{ - .element_type = type_index, - .many = false, - .@"const" = false, - }), - }, + else => unreachable, + // .type_index = try analyzer.getPointerType(.{ + // .element_type = type_index, + // .many = false, + // .@"const" = false, + // }), + // }, }, .flexible_integer => unreachable, else => unreachable, @@ -2027,22 +2018,30 @@ const Analyzer = struct { .slice => blk: { const expression_to_slice_index = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, node.left); const expression_to_slice_type = analyzer.getValueType(expression_to_slice_index); - const element_type = switch (analyzer.module.types.array.get(expression_to_slice_type).*) { - .pointer => |pointer| pointer.element_type, - .slice => |slice| slice.element_type, - else => |t| @panic(@tagName(t)), - }; - const is_const = switch (analyzer.module.types.array.get(expression_to_slice_type).*) { - .pointer => |pointer| pointer.@"const", - .slice => |slice| slice.@"const", - else => |t| @panic(@tagName(t)), - }; + // const element_type = switch ) { + // .pointer => |pointer| pointer.element_type, + // .slice => |slice| slice.element_type, + // else => |t| @panic(@tagName(t)), + // }; + // const is_const = switch (analyzer.module.types.array.get(expression_to_slice_type).*) { + // .pointer => |pointer| pointer.@"const", + // .slice => |slice| slice.@"const", + // else => |t| @panic(@tagName(t)), + // }; const slice_index = try analyzer.module.values.slices.append(analyzer.allocator, .{ .sliceable = expression_to_slice_index, .range = try analyzer.range(scope_index, node.right), - .type = try analyzer.getSliceType(.{ - .element_type = element_type, - .@"const" = is_const, + .type = try analyzer.getSliceType(switch (analyzer.module.types.array.get(expression_to_slice_type).*) { + .pointer => |pointer| .{ + .@"const" = constblk: { + assert(pointer.many); + break :constblk pointer.@"const"; + }, + .element_type = pointer.element_type, + .termination = pointer.termination, + }, + .slice => |slice| slice, + else => |t| @panic(@tagName(t)), }), }); @@ -2090,12 +2089,81 @@ const Analyzer = struct { } }, .undefined => .undefined, + .anonymous_array_literal => blk: { + const array_element_type = switch (expect_type) { + .addressable => |addressable| addr: { + assert(addressable.many); + break :addr addressable.element_type; + }, + .type_index => |type_index| type_index, + else => |t| @panic(@tagName(t)), + }; + const expected_element_count: ?usize = null; + + const array_initialization = try analyzer.analyzeArrayLiteral(scope_index, array_element_type, node.left, expected_element_count); + break :blk .{ + .array_initialization = array_initialization, + }; + }, + .anonymous_container_literal => blk: { + assert(expect_type == .type_index); + const container_initialization = try analyzer.analyzeContainerLiteral(scope_index, expect_type.type_index, node.left); + break :blk .{ + .container_initialization = container_initialization, + }; + }, + .container_literal => blk: { + const list_nodes = analyzer.getScopeNodeList(scope_index, analyzer.getScopeNode(scope_index, node.right)); + const literal_type = try analyzer.resolveType(.{ + .scope_index = scope_index, + .node_index = node.left, + .length_hint = list_nodes.items.len, + }); + const container_initialization = try analyzer.analyzeContainerLiteral(scope_index, literal_type, node.right); + break :blk .{ + .container_initialization = container_initialization, + }; + }, + .anonymous_array_element_initialization => { + try analyzer.resolveNode(value_index, scope_index, expect_type, node.left); + return; + }, else => |t| @panic(@tagName(t)), }; analyzer.module.values.array.get(value_index).* = new_value; } + fn analyzeArrayLiteral(analyzer: *Analyzer, scope_index: Scope.Index, expected_element_type_index: Type.Index, node_list_node_index: Node.Index, expected_element_count: ?usize) !Compilation.ContainerInitialization.Index { + const field_initialization_node_list = analyzer.getScopeNode(scope_index, node_list_node_index); + const field_nodes = analyzer.getScopeNodeList(scope_index, field_initialization_node_list); + assert(!expected_element_type_index.invalid); + + const found_element_count = field_nodes.items.len; + const element_count = if (expected_element_count) |ec| if (ec == found_element_count) ec else @panic("Element count mismatch in array literal") else found_element_count; + + var list = try ArrayList(Value.Index).initCapacity(analyzer.allocator, element_count); + const element_expect_type = ExpectType{ + .type_index = expected_element_type_index, + }; + for (field_nodes.items) |element_node_index| { + const array_element_value_index = try analyzer.unresolvedAllocate(scope_index, element_expect_type, element_node_index); + list.appendAssumeCapacity(array_element_value_index); + // const element_node = analyzer.getScopeNode(scope_index, element_node_index); + } + + const container_initialization_index = try analyzer.module.values.container_initializations.append(analyzer.allocator, .{ + .field_initializations = list, + .type = try analyzer.getArrayType(.{ + .element_count = @intCast(element_count), + .element_type = expected_element_type_index, + .termination = unreachable, + }), + }); + + return container_initialization_index; + } + fn analyzeContainerLiteral(analyzer: *Analyzer, scope_index: Scope.Index, expected_type_index: Type.Index, node_list_node_index: Node.Index) !Compilation.ContainerInitialization.Index { const field_initialization_node_list = analyzer.getScopeNode(scope_index, node_list_node_index); const field_nodes = analyzer.getScopeNodeList(scope_index, field_initialization_node_list); @@ -2105,9 +2173,9 @@ const Analyzer = struct { switch (expected_type.*) { .@"struct" => |struct_index| { const struct_type = analyzer.module.types.structs.get(struct_index); - var bitset = try std.DynamicBitSetUnmanaged.initEmpty(analyzer.allocator, field_nodes.items.len); var list = try ArrayList(Value.Index).initCapacity(analyzer.allocator, struct_type.fields.items.len); + var bitset = try std.DynamicBitSetUnmanaged.initEmpty(analyzer.allocator, field_nodes.items.len); for (struct_type.fields.items) |struct_field_index| { const struct_field = analyzer.module.types.container_fields.get(struct_field_index); @@ -2118,7 +2186,7 @@ const Analyzer = struct { for (field_nodes.items, 0..) |field_node_index, index| { const field_node = analyzer.getScopeNode(scope_index, field_node_index); - assert(field_node.id == .field_initialization); + assert(field_node.id == .container_field_initialization); const identifier = analyzer.tokenIdentifier(scope_index, field_node.token + 1); const identifier_index = try analyzer.processIdentifier(identifier); @@ -2131,7 +2199,7 @@ const Analyzer = struct { value_index = try analyzer.unresolvedAllocate(scope_index, ExpectType{ .type_index = struct_field.type, - }, field_node.right); + }, field_node.left); } } @@ -2165,10 +2233,29 @@ const Analyzer = struct { }); return container_initialization_index; }, + .array => |array_type| { + if (field_nodes.items.len != array_type.element_count) { + unreachable; + } + + const expect_type = ExpectType{ + .type_index = array_type.element_type, + }; + var list = try ArrayList(Value.Index).initCapacity(analyzer.allocator, array_type.element_count); + + for (field_nodes.items) |array_element_node_index| { + const element_value_index = try analyzer.unresolvedAllocate(scope_index, expect_type, array_element_node_index); + list.appendAssumeCapacity(element_value_index); + } + + const container_initialization_index = try analyzer.module.values.container_initializations.append(analyzer.allocator, .{ + .field_initializations = list, + .type = expected_type_index, + }); + return container_initialization_index; + }, else => |t| @panic(@tagName(t)), } - - unreachable; } fn debugNode(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) void { @@ -2198,15 +2285,18 @@ const Analyzer = struct { break :blk original_string_literal; }; const len: u32 = @intCast(string_literal.len); - const array_type = try analyzer.getArrayType(.{ + const array_type_descriptor = Type.Array{ .element_type = Type.u8, .element_count = len, - }); + .termination = .null, + }; + const array_type = try analyzer.getArrayType(array_type_descriptor); const pointer_type = try analyzer.getPointerType(.{ .many = true, .@"const" = true, .element_type = array_type, + .termination = array_type_descriptor.termination, }); const hash = try Module.addString(&analyzer.module.map.strings, analyzer.allocator, string_literal); @@ -2246,6 +2336,7 @@ const Analyzer = struct { fn resolveType(analyzer: *Analyzer, args: struct { scope_index: Scope.Index, node_index: Node.Index, + length_hint: ?usize = null, allow_non_primitive_size: bool = false, }) anyerror!Type.Index { const scope_index = args.scope_index; @@ -2304,64 +2395,23 @@ const Analyzer = struct { }, }; }, - .const_single_pointer_type, - .single_pointer_type, - .const_many_pointer_type, - .many_pointer_type, - .zero_terminated_const_many_pointer_type, - .zero_terminated_many_pointer_type, - => blk: { - const element_type = try resolveType(analyzer, .{ - .scope_index = scope_index, - .node_index = type_node.left, - }); - const many = switch (type_node.id) { - .const_many_pointer_type, - .many_pointer_type, - .zero_terminated_const_many_pointer_type, - .zero_terminated_many_pointer_type, - => true, - .const_single_pointer_type, - .single_pointer_type, - => false, - else => |t| @panic(@tagName(t)), - }; - const is_const = switch (type_node.id) { - .const_many_pointer_type, - .const_single_pointer_type, - .zero_terminated_const_many_pointer_type, - => true, - .zero_terminated_many_pointer_type, - .many_pointer_type, - .single_pointer_type, - => false, - else => |t| @panic(@tagName(t)), - }; + .void_type => Type.void, + .ssize_type => Type.ssize, + .usize_type => Type.usize, + .bool_type => Type.boolean, + .simple_function_prototype => blk: { + const function_prototype_index = try analyzer.module.types.function_prototypes.append(analyzer.allocator, try analyzer.processSimpleFunctionPrototype(scope_index, node_index)); - break :blk try analyzer.getPointerType(.{ - .element_type = element_type, - .many = many, - .@"const" = is_const, + const function_type_index = try analyzer.module.types.array.append(analyzer.allocator, .{ + .function = function_prototype_index, }); + break :blk function_type_index; }, - .slice_type, - .const_slice_type, - => blk: { - const element_type = try resolveType(analyzer, .{ - .scope_index = scope_index, - .node_index = type_node.right, - }); - - const is_const = switch (type_node.id) { - .slice_type => false, - .const_slice_type => true, - else => unreachable, - }; - - break :blk try analyzer.getSliceType(.{ - .element_type = element_type, - .@"const" = is_const, - }); + .field_access => blk: { + const type_value_index = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, node_index); + const type_value_ptr = analyzer.module.values.array.get(type_value_index); + assert(type_value_ptr.* == .type); + break :blk type_value_ptr.type; }, .optional_type => blk: { const element_type = try resolveType(analyzer, .{ @@ -2385,40 +2435,139 @@ const Analyzer = struct { break :blk result; }, - .void_type => Type.void, - .ssize_type => Type.ssize, - .usize_type => Type.usize, - .bool_type => Type.boolean, - .simple_function_prototype => blk: { - const function_prototype_index = try analyzer.module.types.function_prototypes.append(analyzer.allocator, try analyzer.processSimpleFunctionPrototype(scope_index, node_index)); + .pointer_type => blk: { + const list_node = analyzer.getScopeNode(scope_index, type_node.left); + const node_list = analyzer.getScopeNodeList(scope_index, list_node); - const function_type_index = try analyzer.module.types.array.append(analyzer.allocator, .{ - .function = function_prototype_index, + var is_const = false; + var type_index = Type.Index.invalid; + var termination = Termination.none; + var many = false; + + for (node_list.items) |element_node_index| { + const element_node = analyzer.getScopeNode(scope_index, element_node_index); + switch (element_node.id) { + .simple_function_prototype, + .identifier, + .unsigned_integer_type, + .optional_type, + => { + if (!type_index.invalid) { + unreachable; + } + type_index = try analyzer.resolveType(.{ + .scope_index = scope_index, + .node_index = element_node_index, + }); + }, + .const_expression => is_const = true, + .many_pointer_expression => many = true, + .zero_terminated => { + assert(many); + assert(termination == .none); + termination = .zero; + }, + .null_terminated => { + assert(many); + assert(termination == .none); + termination = .null; + }, + else => |t| @panic(@tagName(t)), + } + } + + assert(!type_index.invalid); + + break :blk try analyzer.getPointerType(.{ + .@"const" = is_const, + .many = many, + .element_type = type_index, + .termination = termination, }); - break :blk function_type_index; }, - .field_access => blk: { - const type_value_index = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, node_index); - const type_value_ptr = analyzer.module.values.array.get(type_value_index); - assert(type_value_ptr.* == .type); - break :blk type_value_ptr.type; + .slice_type => blk: { + const list_node = analyzer.getScopeNode(scope_index, type_node.left); + const node_list = analyzer.getScopeNodeList(scope_index, list_node); + + var is_const = false; + var type_index = Type.Index.invalid; + const termination = Termination.none; + + for (node_list.items) |element_node_index| { + const element_node = analyzer.getScopeNode(scope_index, element_node_index); + switch (element_node.id) { + .simple_function_prototype, + .identifier, + .unsigned_integer_type, + => { + if (!type_index.invalid) { + unreachable; + } + type_index = try analyzer.resolveType(.{ + .scope_index = scope_index, + .node_index = element_node_index, + }); + }, + .const_expression => is_const = true, + else => |t| @panic(@tagName(t)), + } + } + + assert(!type_index.invalid); + + break :blk try analyzer.getSliceType(.{ + .@"const" = is_const, + .element_type = type_index, + .termination = termination, + }); }, .array_type => blk: { - const array_element_type_value_index = try analyzer.unresolvedAllocate(scope_index, ExpectType.type, type_node.right); - const array_element_type_value = analyzer.module.values.array.get(array_element_type_value_index); - assert(array_element_type_value.* == .type); - const array_element_type_index = array_element_type_value.type; + const list_node = analyzer.getScopeNode(scope_index, type_node.left); + const node_list = analyzer.getScopeNodeList(scope_index, list_node); - const length_expression_index = try analyzer.unresolvedAllocate(scope_index, ExpectType{ - .type_index = Type.usize, - }, type_node.left); - const length: usize = analyzer.resolveInteger(scope_index, length_expression_index); + var termination: ?Termination = null; + var length_expression: ?usize = null; - const array_type = try analyzer.getArrayType(.{ - .element_type = array_element_type_index, - .element_count = @intCast(length), + for (node_list.items[0 .. node_list.items.len - 1]) |element_node_index| { + const element_node = analyzer.getScopeNode(scope_index, element_node_index); + switch (element_node.id) { + .identifier => { + if (length_expression != null) { + unreachable; + } + + length_expression = analyzer.resolveInteger(scope_index, try analyzer.unresolvedAllocate(scope_index, ExpectType{ + .type_index = Type.usize, + }, element_node_index)); + }, + .discard => { + const length = args.length_hint orelse unreachable; + length_expression = length; + }, + .null_terminated => { + if (termination != null) { + unreachable; + } + termination = .null; + }, + else => |t| @panic(@tagName(t)), + } + } + + assert(length_expression != null); + + const type_index = try analyzer.resolveType(.{ + .scope_index = scope_index, + .node_index = node_list.items[node_list.items.len - 1], + }); + + assert(!type_index.invalid); + + break :blk try analyzer.getArrayType(.{ + .element_type = type_index, + .element_count = length_expression orelse unreachable, + .termination = termination orelse .none, }); - break :blk array_type; }, else => |t| @panic(@tagName(t)), }; @@ -3321,13 +3470,16 @@ const Analyzer = struct { else => |t| @panic(@tagName(t)), } }, - .addressable => |element_type_index| { - const destination_type = analyzer.module.types.array.get(element_type_index); + .addressable => |addressable| { + const destination_type = analyzer.module.types.array.get(addressable.element_type); const source_type = analyzer.module.types.array.get(source); switch (source_type.*) { .array => |array| { - if (array.element_type.eq(element_type_index)) { + assert(addressable.many); + assert(addressable.termination == array.termination); + + if (array.element_type.eq(addressable.element_type)) { return .success; } else { switch (destination_type.*) { @@ -3336,7 +3488,11 @@ const Analyzer = struct { } }, .function => |source_function| { - if (element_type_index.eq(source)) { + assert(!addressable.many); + assert(addressable.termination == .none); + assert(addressable.@"const"); + + if (addressable.element_type.eq(source)) { return .success; } else { switch (destination_type.*) { @@ -3350,12 +3506,14 @@ const Analyzer = struct { }, else => |t| @panic(@tagName(t)), } - unreachable; } }, else => |t| @panic(@tagName(t)), } }, + .dereferenceable => { + unreachable; + }, // else => |t| @panic(@tagName(t)), }; } @@ -3368,6 +3526,7 @@ const Analyzer = struct { .element_type = pointer.element_type, .many = pointer.many, .@"const" = pointer.@"const", + .termination = pointer.termination, }, }); gop.value_ptr.* = type_index; diff --git a/bootstrap/frontend/syntactic_analyzer.zig b/bootstrap/frontend/syntactic_analyzer.zig index edce878..e986998 100644 --- a/bootstrap/frontend/syntactic_analyzer.zig +++ b/bootstrap/frontend/syntactic_analyzer.zig @@ -37,6 +37,7 @@ pub const Logger = enum { suffix, precedence, @"switch", + pointer_like_type_expression, pub var bitset = std.EnumSet(Logger).initMany(&.{ .token_errors, @@ -49,6 +50,7 @@ pub const Logger = enum { .suffix, .precedence, .@"switch", + .pointer_like_type_expression, }); }; @@ -115,7 +117,6 @@ pub const Node = struct { unsigned_integer_type, signed_integer_type, slice_type, - const_slice_type, array_type, argument_declaration, compiler_intrinsic, @@ -123,10 +124,7 @@ pub const Node = struct { usize_type, void_type, call, - const_many_pointer_type, - many_pointer_type, - zero_terminated_const_many_pointer_type, - zero_terminated_many_pointer_type, + pointer_type, enum_literal, address_of, pointer_dereference, @@ -162,7 +160,9 @@ pub const Node = struct { container_field, struct_type, container_literal, - field_initialization, + container_field_initialization, + anonymous_array_element_initialization, + array_index_initialization, boolean_not, null_literal, if_else_payload, @@ -172,8 +172,7 @@ pub const Node = struct { range, negation, anonymous_container_literal, - const_single_pointer_type, - single_pointer_type, + anonymous_array_literal, indexed_access, calling_convention, assembly_register, @@ -183,6 +182,10 @@ pub const Node = struct { for_loop, add_assign, undefined, + zero_terminated, + null_terminated, + const_expression, + many_pointer_expression, }; }; @@ -400,7 +403,6 @@ const Analyzer = struct { var list = ArrayList(Node.Index){}; - var foo = false; while (analyzer.tokens[analyzer.token_i].id != end_token) { const identifier = try analyzer.expectToken(.identifier); _ = try analyzer.expectToken(.colon); @@ -408,7 +410,6 @@ const Analyzer = struct { // const type_expression_node = analyzer.nodes.items[type_expression.unwrap()]; // _ = type_expression_node; // logln("Type expression node: {}", .{type_expression_node}); - foo = true; if (analyzer.tokens[analyzer.token_i].id == .comma) { analyzer.token_i += 1; @@ -844,7 +845,7 @@ const Analyzer = struct { switch (analyzer.tokens[analyzer.token_i].id) { .comma => analyzer.token_i += 1, .right_parenthesis => continue, - else => unreachable, + else => |t| @panic(@tagName(t)), } } @@ -958,6 +959,7 @@ const Analyzer = struct { .fixed_keyword_var, .fixed_keyword_return, .identifier, + .colon, => break, else => blk: { const next_token_index = analyzer.token_i + 1; @@ -1133,6 +1135,7 @@ const Analyzer = struct { .fixed_keyword_struct, .discard, .fixed_keyword_undefined, + .left_bracket, => try analyzer.curlySuffixExpression(), .fixed_keyword_fn => try analyzer.function(), .fixed_keyword_return => try analyzer.addNode(.{ @@ -1194,47 +1197,146 @@ const Analyzer = struct { }); } - fn pointerTypeExpression(analyzer: *Analyzer, arguments: struct { - many: bool, - zero_terminated: bool = false, - start_token: Token.Index, - }) !Node.Index { - const is_const = analyzer.tokens[analyzer.token_i].id == .fixed_keyword_const; - analyzer.token_i += @intFromBool(is_const); - // TODO: handle correctly + const PointerOrArrayTypeExpectedExpression = enum { + single_pointer_type, + many_pointer_type, + array_or_slice_type, + }; + + fn parseTermination(analyzer: *Analyzer) !Node.Index { + _ = try analyzer.expectToken(.colon); + const token = analyzer.tokens[analyzer.token_i]; + const termination_id: Node.Id = switch (token.id) { + .fixed_keyword_null => .null_terminated, + .number_literal => switch (std.zig.parseNumberLiteral(analyzer.source_file[token.start..][0..token.len])) { + .int => |integer| switch (integer) { + 0 => .zero_terminated, + else => @panic("Invalid number literal terminator"), + }, + else => @panic("Invalid number literal terminator"), + }, + else => |t| @panic(@tagName(t)), + }; + + const termination_node_index = try analyzer.addNode(.{ + .id = termination_id, + .token = analyzer.token_i, + .left = Node.Index.invalid, + .right = Node.Index.invalid, + }); + analyzer.token_i += 1; + + return termination_node_index; + } + + fn pointerOrArrayTypeExpression(analyzer: *Analyzer, expected: PointerOrArrayTypeExpectedExpression) !Node.Index { + logln(.parser, .pointer_like_type_expression, "Pointer start", .{}); + const first = analyzer.token_i; + + var list = Node.List{}; + + const expression_type: Node.Id = switch (expected) { + .single_pointer_type => blk: { + analyzer.token_i += 1; + + break :blk .pointer_type; + }, + .many_pointer_type => blk: { + try list.append(analyzer.allocator, try analyzer.addNode(.{ + .id = .many_pointer_expression, + .token = analyzer.token_i, + .left = Node.Index.invalid, + .right = Node.Index.invalid, + })); + _ = try analyzer.expectToken(.left_bracket); + _ = try analyzer.expectToken(.ampersand); + switch (analyzer.tokens[analyzer.token_i].id) { + .right_bracket => {}, + .colon => try list.append(analyzer.allocator, try analyzer.parseTermination()), + else => |t| @panic(@tagName(t)), + } + _ = try analyzer.expectToken(.right_bracket); + + break :blk .pointer_type; + }, + .array_or_slice_type => blk: { + _ = try analyzer.expectToken(.left_bracket); + switch (analyzer.tokens[analyzer.token_i].id) { + .right_bracket => { + analyzer.token_i += 1; + break :blk .slice_type; + }, + .colon => unreachable, + else => { + const length_expression = try analyzer.expression(); + try list.append(analyzer.allocator, length_expression); + + switch (analyzer.tokens[analyzer.token_i].id) { + .right_bracket => {}, + .colon => try list.append(analyzer.allocator, try analyzer.parseTermination()), + else => |t| @panic(@tagName(t)), + } + + _ = try analyzer.expectToken(.right_bracket); + + break :blk .array_type; + }, + } + }, + }; + + if (expression_type != .array_type) { + const const_node = switch (analyzer.tokens[analyzer.token_i].id) { + .fixed_keyword_const => try analyzer.addNode(.{ + .id = .const_expression, + .token = analyzer.token_i, + .left = Node.Index.invalid, + .right = Node.Index.invalid, + }), + else => Node.Index.invalid, + }; + analyzer.token_i += @intFromBool(analyzer.tokens[analyzer.token_i].id == .fixed_keyword_const); + + if (!const_node.invalid) { + try list.append(analyzer.allocator, const_node); + } + } else { + assert(list.items.len > 0); + } + + const type_expression = try analyzer.typeExpression(); + assert(!type_expression.invalid); + try list.append(analyzer.allocator, type_expression); + + const node_list = try analyzer.nodeList(list); + + const node = Node{ + .id = expression_type, + .token = first, + .left = node_list, + .right = Node.Index.invalid, + }; + + logln(.parser, .pointer_like_type_expression, "ARRAY START\n===========", .{}); + for (list.items) |ni| { + const n = analyzer.nodes.items[ni.unwrap()]; + logln(.parser, .pointer_like_type_expression, "{s} node element: {s}", .{ @tagName(expression_type), @tagName(n.id) }); + } + logln(.parser, .pointer_like_type_expression, "ARRAY END\n=========", .{}); + + const node_index = try analyzer.addNode(node); + logln(.parser, .pointer_like_type_expression, "Pointer end", .{}); + switch (analyzer.tokens[analyzer.token_i].id) { - .fixed_keyword_fn => {}, - .identifier => {}, - .keyword_signed_integer, .keyword_unsigned_integer => {}, + .comma, + .right_parenthesis, + .left_brace, + .equal, + => return node_index, else => |t| @panic(@tagName(t)), } - const pointer_element_type = try analyzer.typeExpression(); - if (!arguments.many) { - assert(!arguments.zero_terminated); - } - - return try analyzer.addNode(.{ - .id = switch (arguments.many) { - true => switch (arguments.zero_terminated) { - true => switch (is_const) { - true => .const_many_pointer_type, - false => .many_pointer_type, - }, - false => switch (is_const) { - true => .zero_terminated_const_many_pointer_type, - false => .zero_terminated_many_pointer_type, - }, - }, - false => switch (is_const) { - true => .const_single_pointer_type, - false => .single_pointer_type, - }, - }, - .token = arguments.start_token, - .left = pointer_element_type, - .right = Node.Index.invalid, - }); + return node_index; } fn typeExpression(analyzer: *Analyzer) anyerror!Node.Index { @@ -1250,78 +1352,12 @@ const Analyzer = struct { .right = Node.Index.invalid, }); }, - .ampersand => blk: { - analyzer.token_i += 1; - break :blk try analyzer.pointerTypeExpression(.{ - .many = false, - .start_token = first, - }); - }, // pointer + .ampersand => try analyzer.pointerOrArrayTypeExpression(.single_pointer_type), .bang => unreachable, // error .left_bracket => switch (analyzer.tokens[analyzer.token_i + 1].id) { - .ampersand => blk: { - // many item pointer - analyzer.token_i += 2; - var zero_terminated: bool = false; - if (analyzer.tokens[analyzer.token_i].id == .colon) { - // TODO: parse properly - analyzer.token_i += 1; - zero_terminated = true; - analyzer.token_i += 1; - } - _ = try analyzer.expectToken(.right_bracket); - - break :blk try analyzer.pointerTypeExpression(.{ - .many = true, - .start_token = first, - .zero_terminated = zero_terminated, - }); - }, + .ampersand => try analyzer.pointerOrArrayTypeExpression(.many_pointer_type), .asterisk => @panic("Meant to use ampersand?"), - else => { - const left_bracket = analyzer.token_i; - analyzer.token_i += 1; - // TODO: compute length - const length_expression = switch (analyzer.tokens[analyzer.token_i].id) { - .identifier => try analyzer.expression(), - .right_bracket => Node.Index.invalid, - else => |t| @panic(@tagName(t)), - }; - - _ = try analyzer.expectToken(.right_bracket); - - const is_const = switch (length_expression.invalid) { - true => blk: { - const is_constant = analyzer.tokens[analyzer.token_i].id == .fixed_keyword_const; - analyzer.token_i += @intFromBool(is_constant); - break :blk is_constant; - }, - false => false, - }; - - const type_expression = try analyzer.typeExpression(); - const node = switch (length_expression.invalid) { - false => Node{ - .id = .array_type, - .token = left_bracket, - .left = length_expression, - .right = type_expression, - }, - true => Node{ // TODO: modifiers - .id = switch (is_const) { - true => .const_slice_type, - false => .slice_type, - }, - .token = left_bracket, - .left = Node.Index.invalid, - .right = type_expression, - }, - }; - - const node_index = try analyzer.addNode(node); - - return node_index; - }, + else => try analyzer.pointerOrArrayTypeExpression(.array_or_slice_type), }, }; } @@ -1396,28 +1432,64 @@ const Analyzer = struct { _ = try analyzer.expectToken(.left_brace); var list = ArrayList(Node.Index){}; + const InitializationType = enum { + anonymous, + array_indices, + container_field_names, + }; + + var current_initialization: ?InitializationType = null; while (analyzer.tokens[analyzer.token_i].id != .right_brace) { const start_token = analyzer.token_i; - switch (analyzer.tokens[start_token].id) { - .period => { + const iteration_initialization_type: InitializationType = switch (analyzer.tokens[start_token].id) { + .period => blk: { analyzer.token_i += 1; _ = try analyzer.expectToken(.identifier); _ = try analyzer.expectToken(.equal); const field_expression_initializer = try analyzer.expression(); - _ = try analyzer.expectToken(.comma); const field_initialization = try analyzer.addNode(.{ - .id = .field_initialization, + .id = .container_field_initialization, .token = start_token, - .left = Node.Index.invalid, - .right = field_expression_initializer, + .left = field_expression_initializer, + .right = Node.Index.invalid, }); try list.append(analyzer.allocator, field_initialization); + _ = try analyzer.expectToken(.comma); + + break :blk .container_field_names; + }, + .string_literal, + .identifier, + => blk: { + const field_expression_initializer = try analyzer.expression(); + switch (analyzer.tokens[analyzer.token_i].id) { + .comma => analyzer.token_i += 1, + else => {}, + } + + const field_initialization = try analyzer.addNode(.{ + .id = .anonymous_array_element_initialization, + .token = start_token, + .left = field_expression_initializer, + .right = Node.Index.invalid, + }); + + try list.append(analyzer.allocator, field_initialization); + break :blk .anonymous; }, else => |t| @panic(@tagName(t)), + }; + + if (current_initialization) |ci| { + if (ci != iteration_initialization_type) { + unreachable; + } } + + current_initialization = iteration_initialization_type; } _ = try analyzer.expectToken(.right_brace); @@ -1425,6 +1497,34 @@ const Analyzer = struct { return try analyzer.nodeList(list); } + fn arrayInitialization(analyzer: *Analyzer) !Node.Index { + _ = try analyzer.expectToken(.left_bracket); + var list = ArrayList(Node.Index){}; + while (analyzer.tokens[analyzer.token_i].id != .right_bracket) { + const node_index: Node.Index = switch (analyzer.tokens[analyzer.token_i].id) { + .left_bracket => @panic("Left bracket"), + else => Node.Index.invalid, + }; + + const initialization_node = try analyzer.expression(); + const node = switch (node_index.invalid) { + true => initialization_node, + false => @panic("left bracket"), + }; + + try list.append(analyzer.allocator, node); + + switch (analyzer.tokens[analyzer.token_i].id) { + .comma => analyzer.token_i += 1, + .right_bracket => {}, + else => |t| @panic(@tagName(t)), + } + } + _ = try analyzer.expectToken(.right_bracket); + + return try analyzer.nodeList(list); + } + fn discardNode(analyzer: *Analyzer) !Node.Index { const token = analyzer.token_i; assert(analyzer.tokens[token].id == .discard); @@ -1560,6 +1660,15 @@ const Analyzer = struct { .left = try analyzer.fieldInitialization(), .right = Node.Index.invalid, }), + .left_bracket => try analyzer.addNode(.{ + .id = .anonymous_array_literal, + .token = blk: { + analyzer.token_i += 1; + break :blk token_i; + }, + .left = try analyzer.arrayInitialization(), + .right = Node.Index.invalid, + }), else => |t| @panic(@tagName(t)), }, .fixed_keyword_enum => blk: { @@ -1704,6 +1813,9 @@ const Analyzer = struct { fn addNode(analyzer: *Analyzer, node: Node) !Node.Index { const index = analyzer.nodes.items.len; try analyzer.nodes.append(analyzer.allocator, node); + // if (index == 38 or index == 37) { + // @breakpoint(); + // } logln(.parser, .node_creation, "Adding node #{} (0x{x}) {s} to file #{}", .{ index, @intFromPtr(&analyzer.nodes.items[index]), @tagName(node.id), analyzer.file_index.uniqueInteger() }); // if (node.id == .identifier) { // logln("Node identifier: {s}", .{analyzer.bytes(node.token)}); @@ -1755,7 +1867,7 @@ const Analyzer = struct { .right = Node.Index.invalid, }); }, - else => |foo| @panic(@tagName(foo)), + else => |t| @panic(@tagName(t)), }, .identifier => blk: { analyzer.token_i += 1; diff --git a/lib/std/os.nat b/lib/std/os.nat index 3ec2a96..ad87e2c 100644 --- a/lib/std/os.nat +++ b/lib/std/os.nat @@ -114,6 +114,15 @@ const duplicate_process = fn () ?ProcessId { } } +const execute = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) usize { + switch (current) { + .linux => { + return linux.execve(path, argv, env); + }, + else => #error("OS not supported"), + } +} + const FileDescriptor = struct{ handle: system.FileDescriptor, diff --git a/lib/std/os/linux.nat b/lib/std/os/linux.nat index 1d7aeb4..78246be 100644 --- a/lib/std/os/linux.nat +++ b/lib/std/os/linux.nat @@ -430,6 +430,11 @@ const fork = fn() usize { return result; } +const execve = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) usize { + const result = #syscall(#cast(Syscall.execve), #cast(path), #cast(argv), #cast(env)); + return result; +} + const unwrapSyscall = fn(syscall_result: usize) ?usize { const signed_syscall_result: ssize = #cast(syscall_result); if (signed_syscall_result >= 0) { diff --git a/src/main.nat b/src/main.nat index 1f168cb..6fcbf13 100644 --- a/src/main.nat +++ b/src/main.nat @@ -2,6 +2,7 @@ const std = #import("std"); const main = fn() s32 { const size = 0x1000; + if (std.page_allocator.allocate(size, alignment = 12)) |result| { result[0] = 0; std.print(bytes = "Allocation succeeded. Freeing...\n"); @@ -9,7 +10,7 @@ const main = fn() s32 { std.print(bytes = "Memory freed successfully\n"); return 0; } else { - std.print("Memory freed with errors\n"); + std.print(bytes = "Memory freed with errors\n"); return 1; } } else { diff --git a/test/fork_exec/main.nat b/test/fork_exec/main.nat new file mode 100644 index 0000000..faf1aac --- /dev/null +++ b/test/fork_exec/main.nat @@ -0,0 +1,18 @@ +const std = #import("std"); +const main = fn() s32{ + if (std.os.duplicate_process()) |pid| { + if (pid == 0) { + std.print(bytes = "Hello from child\n"); + const argv = [_:null] ?[&:0]const u8{"/usr/bin/ls"}; + const env = [_:null] ?[&:null]const u8 {}; + std.os.execute(path = "/usr/bin/ls", argv = argv.&, env = env.&); + return 1; + } else { + std.print(bytes = "Hello from parent\n"); + return 0; + } + } else { + std.print(bytes = "Unable to create child process\n"); + return 1; + } +}