Merge pull request #31 from birth-software/exec

Implement exec
This commit is contained in:
David 2023-12-08 01:36:19 +01:00 committed by GitHub
commit 57325e4530
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 897 additions and 428 deletions

View File

@ -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 => {

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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) {

View File

@ -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
View 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;
}
}