commit
57325e4530
@ -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 => {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
18
test/fork_exec/main.nat
Normal file
18
test/fork_exec/main.nat
Normal file
@ -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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user