Merge pull request #27 from birth-software/current-executable-path
implement current executable path
This commit is contained in:
commit
1a4d6d36c4
@ -21,9 +21,7 @@ const Token = lexical_analyzer.Token;
|
||||
const syntactic_analyzer = @import("frontend/syntactic_analyzer.zig");
|
||||
const Node = syntactic_analyzer.Node;
|
||||
const semantic_analyzer = @import("frontend/semantic_analyzer.zig");
|
||||
const intermediate_representation = @import("backend/intermediate_representation.zig");
|
||||
const c_transpiler = @import("backend/c_transpiler.zig");
|
||||
const emit = @import("backend/emit.zig");
|
||||
|
||||
test {
|
||||
_ = lexical_analyzer;
|
||||
@ -55,7 +53,7 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
||||
var maybe_executable_path: ?[]const u8 = null;
|
||||
var maybe_main_package_path: ?[]const u8 = null;
|
||||
var target_triplet: []const u8 = "x86_64-linux-gnu";
|
||||
var transpile_to_c: ?bool = null;
|
||||
var should_transpile_to_c: ?bool = null;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < arguments.len) : (i += 1) {
|
||||
@ -121,9 +119,9 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
||||
|
||||
const arg = arguments[i];
|
||||
if (std.mem.eql(u8, arg, "true")) {
|
||||
transpile_to_c = true;
|
||||
should_transpile_to_c = true;
|
||||
} else if (std.mem.eql(u8, arg, "false")) {
|
||||
transpile_to_c = false;
|
||||
should_transpile_to_c = false;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
@ -135,23 +133,33 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
||||
}
|
||||
}
|
||||
|
||||
const main_package_path = maybe_main_package_path orelse return error.main_package_path_not_specified;
|
||||
const cross_target = try std.zig.CrossTarget.parse(.{ .arch_os_abi = target_triplet });
|
||||
const target = cross_target.toTarget();
|
||||
const transpile_to_c = should_transpile_to_c orelse true;
|
||||
|
||||
var is_build = false;
|
||||
const main_package_path = if (maybe_main_package_path) |path| path else blk: {
|
||||
const build_file = "build.nat";
|
||||
const file = std.fs.cwd().openFile(build_file, .{}) catch return error.main_package_path_not_specified;
|
||||
file.close();
|
||||
is_build = true;
|
||||
|
||||
break :blk build_file;
|
||||
};
|
||||
|
||||
const executable_path = maybe_executable_path orelse blk: {
|
||||
const executable_name = std.fs.path.basename(main_package_path[0 .. main_package_path.len - "/main.nat".len]);
|
||||
const executable_name = if (is_build) "build" else std.fs.path.basename(main_package_path[0 .. main_package_path.len - "/main.nat".len]);
|
||||
assert(executable_name.len > 0);
|
||||
const result = try std.mem.concat(allocator, u8, &.{ "nat/", executable_name });
|
||||
break :blk result;
|
||||
};
|
||||
|
||||
const cross_target = try std.zig.CrossTarget.parse(.{ .arch_os_abi = target_triplet });
|
||||
const target = cross_target.toTarget();
|
||||
|
||||
return .{
|
||||
.main_package_path = main_package_path,
|
||||
.executable_path = executable_path,
|
||||
.target = target,
|
||||
.transpile_to_c = transpile_to_c orelse true,
|
||||
.transpile_to_c = transpile_to_c,
|
||||
.is_build = is_build,
|
||||
};
|
||||
}
|
||||
|
||||
@ -183,7 +191,6 @@ pub const Struct = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const ContainerField = struct {
|
||||
@ -194,7 +201,6 @@ pub const ContainerField = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const ContainerInitialization = struct {
|
||||
@ -203,7 +209,6 @@ pub const ContainerInitialization = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Enum = struct {
|
||||
@ -218,21 +223,10 @@ pub const Enum = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = Enum.Field.List.Index;
|
||||
pub const Allocation = Enum.Field.List.Allocation;
|
||||
};
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Array = struct {
|
||||
element_type: Type.Index,
|
||||
element_count: u32,
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Type = union(enum) {
|
||||
@ -255,6 +249,11 @@ pub const Type = union(enum) {
|
||||
element_type: Type.Index,
|
||||
};
|
||||
|
||||
pub const Array = struct {
|
||||
element_type: Type.Index,
|
||||
element_count: u32,
|
||||
};
|
||||
|
||||
pub const Slice = struct {
|
||||
element_type: Type.Index,
|
||||
@"const": bool,
|
||||
@ -268,7 +267,6 @@ pub const Type = union(enum) {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
|
||||
pub const Integer = struct {
|
||||
bit_count: u16,
|
||||
@ -434,7 +432,6 @@ pub const Scope = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const ScopeType = enum(u1) {
|
||||
@ -463,7 +460,6 @@ pub const Declaration = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Function = struct {
|
||||
@ -500,7 +496,6 @@ pub const Function = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Block = struct {
|
||||
@ -508,7 +503,6 @@ pub const Block = struct {
|
||||
reaches_end: bool,
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Loop = struct {
|
||||
@ -520,7 +514,6 @@ pub const Loop = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
const Unresolved = struct {
|
||||
@ -539,7 +532,6 @@ pub const Assignment = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Syscall = struct {
|
||||
@ -553,7 +545,6 @@ pub const Syscall = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Call = struct {
|
||||
@ -563,21 +554,18 @@ pub const Call = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const ArgumentList = struct {
|
||||
array: ArrayList(Value.Index),
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Return = struct {
|
||||
value: Value.Index,
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Cast = struct {
|
||||
@ -586,7 +574,6 @@ pub const Cast = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const BinaryOperation = struct {
|
||||
@ -597,7 +584,6 @@ pub const BinaryOperation = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
|
||||
pub const Id = enum {
|
||||
add,
|
||||
@ -624,7 +610,6 @@ pub const UnaryOperation = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
|
||||
pub const Id = enum {
|
||||
boolean_not,
|
||||
@ -647,7 +632,6 @@ pub const Branch = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const FieldAccess = struct {
|
||||
@ -656,7 +640,6 @@ pub const FieldAccess = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Range = struct {
|
||||
@ -676,7 +659,6 @@ pub const Slice = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = Slice.Access.List.Index;
|
||||
pub const Allocation = Slice.Access.List.Allocation;
|
||||
};
|
||||
|
||||
pub const Field = enum {
|
||||
@ -686,7 +668,6 @@ pub const Slice = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const IndexedAccess = struct {
|
||||
@ -695,7 +676,6 @@ pub const IndexedAccess = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const OptionalCheck = struct {
|
||||
@ -703,7 +683,6 @@ pub const OptionalCheck = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const OptionalUnwrap = struct {
|
||||
@ -711,7 +690,6 @@ pub const OptionalUnwrap = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Assembly = struct {
|
||||
@ -721,7 +699,6 @@ pub const Assembly = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Operand = union(enum) {
|
||||
@ -735,7 +712,6 @@ pub const Assembly = struct {
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const x86_64 = struct {
|
||||
@ -752,6 +728,11 @@ pub const Assembly = struct {
|
||||
};
|
||||
};
|
||||
|
||||
pub const StringLiteral = struct {
|
||||
hash: u32,
|
||||
type: Type.Index,
|
||||
};
|
||||
|
||||
pub const Value = union(enum) {
|
||||
void,
|
||||
bool: bool,
|
||||
@ -774,7 +755,7 @@ pub const Value = union(enum) {
|
||||
argument_list: ArgumentList,
|
||||
@"return": Return.Index,
|
||||
argument: Declaration.Index,
|
||||
string_literal: u32,
|
||||
string_literal: StringLiteral,
|
||||
enum_field: Enum.Field.Index,
|
||||
extern_function: Function.Prototype.Index,
|
||||
sign_extend: Cast.Index,
|
||||
@ -789,12 +770,13 @@ pub const Value = union(enum) {
|
||||
indexed_access: IndexedAccess.Index,
|
||||
optional_check: OptionalCheck.Index,
|
||||
optional_unwrap: OptionalUnwrap.Index,
|
||||
optional_cast: Cast.Index,
|
||||
array_coerce_to_slice: Cast.Index,
|
||||
slice: Slice.Index,
|
||||
assembly_block: Assembly.Block.Index,
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
|
||||
pub const Integer = struct {
|
||||
value: u64,
|
||||
@ -809,7 +791,7 @@ pub const Value = union(enum) {
|
||||
pub fn isComptime(value: *Value, module: *Module) bool {
|
||||
return switch (value.*) {
|
||||
.integer => |integer| integer.type.eq(Type.comptime_int),
|
||||
.declaration_reference => |declaration_reference| module.declarations.get(declaration_reference.value).mutability == .@"const" and isComptime(module.values.get(module.declarations.get(declaration_reference.value).init_value), module),
|
||||
.declaration_reference => |declaration_reference| module.values.declarations.get(declaration_reference.value).mutability == .@"const" and isComptime(module.values.array.get(module.values.declarations.get(declaration_reference.value).init_value), module),
|
||||
.bool, .void, .undefined, .function_definition, .type, .enum_field => true,
|
||||
// TODO:
|
||||
.call,
|
||||
@ -820,6 +802,7 @@ pub const Value = union(enum) {
|
||||
.optional_unwrap,
|
||||
.pointer_null_literal,
|
||||
.indexed_access,
|
||||
.slice,
|
||||
=> false,
|
||||
// TODO:
|
||||
else => |t| @panic(@tagName(t)),
|
||||
@ -828,31 +811,34 @@ pub const Value = union(enum) {
|
||||
|
||||
pub fn getType(value: Value, module: *Module) Type.Index {
|
||||
const result = switch (value) {
|
||||
.call => |call_index| module.calls.get(call_index).type,
|
||||
.call => |call_index| module.values.calls.get(call_index).type,
|
||||
.integer => |integer| integer.type,
|
||||
.declaration_reference => |declaration_reference| declaration_reference.type,
|
||||
.string_literal => |string_literal_hash| module.string_literal_types.get(@intCast(module.getStringLiteral(string_literal_hash).?.len)).?,
|
||||
.string_literal => |string_literal| string_literal.type,
|
||||
.type => Type.type,
|
||||
.enum_field => |enum_field_index| module.enums.get(module.enum_fields.get(enum_field_index).parent).type,
|
||||
.function_definition => |function_index| module.function_definitions.get(function_index).prototype,
|
||||
.function_declaration => |function_index| module.function_declarations.get(function_index).prototype,
|
||||
.binary_operation => |binary_operation| module.binary_operations.get(binary_operation).type,
|
||||
.enum_field => |enum_field_index| module.types.enums.get(module.types.enum_fields.get(enum_field_index).parent).type,
|
||||
.function_definition => |function_index| module.types.function_definitions.get(function_index).prototype,
|
||||
.function_declaration => |function_index| module.types.function_declarations.get(function_index).prototype,
|
||||
.binary_operation => |binary_operation| module.values.binary_operations.get(binary_operation).type,
|
||||
.bool => Type.boolean,
|
||||
.declaration => Type.void,
|
||||
.container_initialization => |container_initialization| module.container_initializations.get(container_initialization).type,
|
||||
.container_initialization => |container_initialization| module.values.container_initializations.get(container_initialization).type,
|
||||
.syscall => Type.usize,
|
||||
.unary_operation => |unary_operation_index| module.unary_operations.get(unary_operation_index).type,
|
||||
.unary_operation => |unary_operation_index| module.values.unary_operations.get(unary_operation_index).type,
|
||||
.pointer_null_literal => semantic_analyzer.optional_pointer_to_any_type,
|
||||
.optional_null_literal => semantic_analyzer.optional_any,
|
||||
.field_access => |field_access_index| module.container_fields.get(module.field_accesses.get(field_access_index).field).type,
|
||||
.cast => |cast_index| module.casts.get(cast_index).type,
|
||||
.slice => |slice_index| module.slices.get(slice_index).type,
|
||||
.slice_access => |slice_access_index| module.slice_accesses.get(slice_access_index).type,
|
||||
.field_access => |field_access_index| module.types.container_fields.get(module.values.field_accesses.get(field_access_index).field).type,
|
||||
.cast,
|
||||
.optional_cast,
|
||||
.array_coerce_to_slice,
|
||||
=> |cast_index| module.values.casts.get(cast_index).type,
|
||||
.slice => |slice_index| module.values.slices.get(slice_index).type,
|
||||
.slice_access => |slice_access_index| module.values.slice_accesses.get(slice_access_index).type,
|
||||
.optional_check => Type.boolean,
|
||||
.indexed_access => |indexed_access_index| blk: {
|
||||
const indexed_expression = module.values.get(module.indexed_accesses.get(indexed_access_index).indexed_expression);
|
||||
const indexed_expression = module.values.array.get(module.values.indexed_accesses.get(indexed_access_index).indexed_expression);
|
||||
const indexed_expression_type_index = indexed_expression.getType(module);
|
||||
const indexed_expression_type = module.types.get(indexed_expression_type_index);
|
||||
const indexed_expression_type = module.types.array.get(indexed_expression_type_index);
|
||||
break :blk switch (indexed_expression_type.*) {
|
||||
.slice => |slice| slice.element_type,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
@ -872,18 +858,12 @@ pub const Value = union(enum) {
|
||||
};
|
||||
|
||||
pub const Module = struct {
|
||||
main_package: *Package,
|
||||
import_table: StringArrayHashMap(*File) = .{},
|
||||
string_table: StringKeyMap([]const u8) = .{},
|
||||
values: struct {
|
||||
field_accesses: BlockList(FieldAccess) = .{},
|
||||
array: BlockList(Value) = .{},
|
||||
declarations: BlockList(Declaration) = .{},
|
||||
structs: BlockList(Struct) = .{},
|
||||
scopes: BlockList(Scope) = .{},
|
||||
files: BlockList(File) = .{},
|
||||
values: BlockList(Value) = .{},
|
||||
function_definitions: BlockList(Function) = .{},
|
||||
function_declarations: BlockList(Function) = .{},
|
||||
function_prototypes: BlockList(Function.Prototype) = .{},
|
||||
types: BlockList(Type) = .{},
|
||||
blocks: BlockList(Block) = .{},
|
||||
loops: BlockList(Loop) = .{},
|
||||
assignments: BlockList(Assignment) = .{},
|
||||
@ -891,19 +871,11 @@ pub const Module = struct {
|
||||
calls: BlockList(Call) = .{},
|
||||
argument_lists: BlockList(ArgumentList) = .{},
|
||||
returns: BlockList(Return) = .{},
|
||||
string_literals: StringKeyMap([]const u8) = .{},
|
||||
enums: BlockList(Enum) = .{},
|
||||
enum_fields: BlockList(Enum.Field) = .{},
|
||||
container_fields: BlockList(ContainerField) = .{},
|
||||
container_initializations: BlockList(ContainerInitialization) = .{},
|
||||
function_map: data_structures.AutoArrayHashMap(Function.Index, Declaration.Index) = .{},
|
||||
type_map: data_structures.AutoArrayHashMap(Type.Index, Declaration.Index) = .{},
|
||||
arrays: BlockList(Array) = .{},
|
||||
casts: BlockList(Cast) = .{},
|
||||
branches: BlockList(Branch) = .{},
|
||||
binary_operations: BlockList(BinaryOperation) = .{},
|
||||
unary_operations: BlockList(UnaryOperation) = .{},
|
||||
branches: BlockList(Branch) = .{},
|
||||
field_accesses: BlockList(FieldAccess) = .{},
|
||||
slices: BlockList(Slice) = .{},
|
||||
slice_accesses: BlockList(Slice.Access) = .{},
|
||||
indexed_accesses: BlockList(IndexedAccess) = .{},
|
||||
@ -911,12 +883,30 @@ pub const Module = struct {
|
||||
optional_unwraps: BlockList(OptionalUnwrap) = .{},
|
||||
assembly_blocks: BlockList(Assembly.Block) = .{},
|
||||
assembly_instructions: BlockList(Assembly.Instruction) = .{},
|
||||
non_primitive_integer_types: data_structures.AutoArrayHashMap(Type.Integer, Type.Index) = .{},
|
||||
string_literal_types: data_structures.AutoArrayHashMap(u32, Type.Index) = .{},
|
||||
slice_types: data_structures.AutoArrayHashMap(Type.Slice, Type.Index) = .{},
|
||||
pointer_types: data_structures.AutoArrayHashMap(Type.Pointer, Type.Index) = .{},
|
||||
optional_types: data_structures.AutoArrayHashMap(Type.Index, Type.Index) = .{},
|
||||
array_types: data_structures.AutoArrayHashMap(Array, Type.Index) = .{},
|
||||
} = .{},
|
||||
types: struct {
|
||||
array: BlockList(Type) = .{},
|
||||
enums: BlockList(Enum) = .{},
|
||||
arrays: BlockList(Type.Array) = .{},
|
||||
structs: BlockList(Struct) = .{},
|
||||
container_fields: BlockList(ContainerField) = .{},
|
||||
enum_fields: BlockList(Enum.Field) = .{},
|
||||
function_definitions: BlockList(Function) = .{},
|
||||
function_declarations: BlockList(Function) = .{},
|
||||
function_prototypes: BlockList(Function.Prototype) = .{},
|
||||
} = .{},
|
||||
map: struct {
|
||||
functions: data_structures.AutoArrayHashMap(Function.Index, Declaration.Index) = .{},
|
||||
strings: StringKeyMap([]const u8) = .{},
|
||||
imports: StringArrayHashMap(File.Index) = .{},
|
||||
types: data_structures.AutoArrayHashMap(Type.Index, Declaration.Index) = .{},
|
||||
non_primitive_integer: data_structures.AutoArrayHashMap(Type.Integer, Type.Index) = .{},
|
||||
slices: data_structures.AutoArrayHashMap(Type.Slice, Type.Index) = .{},
|
||||
pointers: data_structures.AutoArrayHashMap(Type.Pointer, Type.Index) = .{},
|
||||
optionals: data_structures.AutoArrayHashMap(Type.Index, Type.Index) = .{},
|
||||
arrays: data_structures.AutoArrayHashMap(Type.Array, Type.Index) = .{},
|
||||
} = .{},
|
||||
main_package: *Package,
|
||||
entry_point: Function.Index = Function.Index.invalid,
|
||||
descriptor: Descriptor,
|
||||
|
||||
@ -925,10 +915,10 @@ pub const Module = struct {
|
||||
executable_path: []const u8,
|
||||
target: std.Target,
|
||||
transpile_to_c: bool,
|
||||
is_build: bool,
|
||||
};
|
||||
|
||||
const ImportFileResult = struct {
|
||||
ptr: *File,
|
||||
index: File.Index,
|
||||
is_new: bool,
|
||||
};
|
||||
@ -952,7 +942,7 @@ pub const Module = struct {
|
||||
return module.importPackage(allocator, module.main_package);
|
||||
}
|
||||
|
||||
const current_file = module.files.get(current_file_index);
|
||||
const current_file = module.values.files.get(current_file_index);
|
||||
if (current_file.package.dependencies.get(import_name)) |package| {
|
||||
return module.importPackage(allocator, package);
|
||||
}
|
||||
@ -968,7 +958,7 @@ pub const Module = struct {
|
||||
const package = current_file.package;
|
||||
const import_file = try module.getFile(allocator, full_path, file_relative_path, package);
|
||||
|
||||
try import_file.ptr.addFileReference(allocator, current_file);
|
||||
try module.values.files.get(import_file.index).file_references.append(allocator, current_file);
|
||||
|
||||
const result = ImportPackageResult{
|
||||
.file = import_file,
|
||||
@ -979,33 +969,22 @@ pub const Module = struct {
|
||||
}
|
||||
|
||||
fn getFile(module: *Module, allocator: Allocator, full_path: []const u8, relative_path: []const u8, package: *Package) !ImportFileResult {
|
||||
const path_lookup = try module.import_table.getOrPut(allocator, full_path);
|
||||
const file, const index = switch (path_lookup.found_existing) {
|
||||
true => blk: {
|
||||
const result = path_lookup.value_ptr.*;
|
||||
const index = module.files.indexOf(result);
|
||||
break :blk .{
|
||||
result,
|
||||
index,
|
||||
};
|
||||
},
|
||||
const path_lookup = try module.map.imports.getOrPut(allocator, full_path);
|
||||
const index = switch (path_lookup.found_existing) {
|
||||
true => path_lookup.value_ptr.*,
|
||||
false => blk: {
|
||||
const file_allocation = try module.files.append(allocator, File{
|
||||
const file_index = try module.values.files.append(allocator, File{
|
||||
.relative_path = relative_path,
|
||||
.package = package,
|
||||
});
|
||||
logln(.compilation, .new_file, "Adding file #{}: {s}\n", .{ file_allocation.index.uniqueInteger(), full_path });
|
||||
path_lookup.value_ptr.* = file_allocation.ptr;
|
||||
logln(.compilation, .new_file, "Adding file #{}: {s}\n", .{ file_index.uniqueInteger(), full_path });
|
||||
path_lookup.value_ptr.* = file_index;
|
||||
// break :blk file;
|
||||
break :blk .{
|
||||
file_allocation.ptr,
|
||||
file_allocation.index,
|
||||
};
|
||||
break :blk file_index;
|
||||
},
|
||||
};
|
||||
|
||||
return .{
|
||||
.ptr = file,
|
||||
.index = index,
|
||||
.is_new = !path_lookup.found_existing,
|
||||
};
|
||||
@ -1015,7 +994,8 @@ pub const Module = struct {
|
||||
const full_path = try std.fs.path.resolve(allocator, &.{ package.directory.path, package.source_path });
|
||||
logln(.compilation, .import, "Import full path: {s}\n", .{full_path});
|
||||
const import_file = try module.getFile(allocator, full_path, package.source_path, package);
|
||||
try import_file.ptr.addPackageReference(allocator, package);
|
||||
const file = module.values.files.get(import_file.index);
|
||||
try file.addPackageReference(allocator, package);
|
||||
|
||||
return .{
|
||||
.file = import_file,
|
||||
@ -1024,7 +1004,7 @@ pub const Module = struct {
|
||||
}
|
||||
|
||||
pub fn generateAbstractSyntaxTreeForFile(module: *Module, allocator: Allocator, file_index: File.Index) !void {
|
||||
const file = module.files.get(file_index);
|
||||
const file = module.values.files.get(file_index);
|
||||
const source_file = file.package.directory.handle.openFile(file.relative_path, .{}) catch |err| {
|
||||
std.debug.panic("Can't find file {s} in directory {s} for error {s}", .{ file.relative_path, file.package.directory.path, @errorName(err) });
|
||||
};
|
||||
@ -1048,54 +1028,17 @@ pub const Module = struct {
|
||||
return map.getValue(key);
|
||||
}
|
||||
|
||||
fn addString(map: *StringKeyMap([]const u8), allocator: Allocator, string: []const u8) !u32 {
|
||||
pub fn addString(map: *StringKeyMap([]const u8), allocator: Allocator, string: []const u8) !u32 {
|
||||
const lookup_result = try map.getOrPut(allocator, string, string);
|
||||
return lookup_result.key;
|
||||
}
|
||||
|
||||
pub fn getName(module: *Module, key: u32) ?[]const u8 {
|
||||
return getString(&module.string_table, key);
|
||||
return getString(&module.map.strings, key);
|
||||
}
|
||||
|
||||
pub fn addName(module: *Module, allocator: Allocator, name: []const u8) !u32 {
|
||||
return addString(&module.string_table, allocator, name);
|
||||
}
|
||||
|
||||
pub fn getStringLiteral(module: *Module, key: u32) ?[]const u8 {
|
||||
return getString(&module.string_literals, key);
|
||||
}
|
||||
|
||||
pub fn addStringLiteral(module: *Module, allocator: Allocator, string_literal: []const u8) !u32 {
|
||||
const result = addString(&module.string_literals, allocator, string_literal);
|
||||
|
||||
const len: u32 = @intCast(string_literal.len);
|
||||
// try analyzer.module.
|
||||
const string_literal_type_gop = try module.string_literal_types.getOrPut(allocator, len);
|
||||
if (!string_literal_type_gop.found_existing) {
|
||||
const array = Array{
|
||||
.element_type = Type.u8,
|
||||
.element_count = len,
|
||||
};
|
||||
const array_type_gop = try module.array_types.getOrPut(allocator, array);
|
||||
if (!array_type_gop.found_existing) {
|
||||
const array_type_allocation = try module.types.append(allocator, .{
|
||||
.array = array,
|
||||
});
|
||||
array_type_gop.value_ptr.* = array_type_allocation.index;
|
||||
}
|
||||
|
||||
const array_type_index = array_type_gop.value_ptr.*;
|
||||
const pointer_type_allocation = try module.types.append(allocator, .{
|
||||
.pointer = .{
|
||||
.@"const" = true,
|
||||
.many = true,
|
||||
.element_type = array_type_index,
|
||||
},
|
||||
});
|
||||
string_literal_type_gop.value_ptr.* = pointer_type_allocation.index;
|
||||
}
|
||||
|
||||
return result;
|
||||
return addString(&module.map.strings, allocator, name);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1135,7 +1078,10 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
||||
module.* = Module{
|
||||
.main_package = blk: {
|
||||
const result = try compilation.base_allocator.create(Package);
|
||||
const main_package_absolute_directory_path = try compilation.pathFromCwd(std.fs.path.dirname(descriptor.main_package_path).?);
|
||||
const main_package_absolute_directory_path = b: {
|
||||
const relative_path = if (std.fs.path.dirname(descriptor.main_package_path)) |dirname| dirname else ".";
|
||||
break :b try compilation.pathFromCwd(relative_path);
|
||||
};
|
||||
result.* = .{
|
||||
.directory = .{
|
||||
.handle = try std.fs.openDirAbsolute(main_package_absolute_directory_path, .{}),
|
||||
@ -1188,12 +1134,12 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
||||
|
||||
_ = try module.importPackage(compilation.base_allocator, module.main_package.dependencies.get("std").?);
|
||||
|
||||
for (module.import_table.values()) |import| {
|
||||
try module.generateAbstractSyntaxTreeForFile(compilation.base_allocator, module.files.indexOf(import));
|
||||
for (module.map.imports.values()) |import| {
|
||||
try module.generateAbstractSyntaxTreeForFile(compilation.base_allocator, import);
|
||||
}
|
||||
|
||||
inline for (@typeInfo(FixedTypeKeyword).Enum.fields) |enum_field| {
|
||||
_ = try module.types.append(compilation.base_allocator, switch (@field(FixedTypeKeyword, enum_field.name)) {
|
||||
_ = try module.types.array.append(compilation.base_allocator, switch (@field(FixedTypeKeyword, enum_field.name)) {
|
||||
.usize => @unionInit(Type, "integer", .{
|
||||
.bit_count = 64,
|
||||
.signedness = .unsigned,
|
||||
@ -1207,7 +1153,7 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
||||
}
|
||||
|
||||
inline for (@typeInfo(HardwareUnsignedIntegerType).Enum.fields) |enum_field| {
|
||||
_ = try module.types.append(compilation.base_allocator, .{
|
||||
_ = try module.types.array.append(compilation.base_allocator, .{
|
||||
.integer = .{
|
||||
.signedness = .unsigned,
|
||||
.bit_count = switch (@field(HardwareUnsignedIntegerType, enum_field.name)) {
|
||||
@ -1221,7 +1167,7 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
||||
}
|
||||
|
||||
inline for (@typeInfo(HardwareSignedIntegerType).Enum.fields) |enum_field| {
|
||||
_ = try module.types.append(compilation.base_allocator, .{
|
||||
_ = try module.types.array.append(compilation.base_allocator, .{
|
||||
.integer = .{
|
||||
.signedness = .signed,
|
||||
.bit_count = switch (@field(HardwareSignedIntegerType, enum_field.name)) {
|
||||
@ -1235,37 +1181,38 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
||||
}
|
||||
|
||||
for (extra_common_type_data) |type_data| {
|
||||
_ = try module.types.append(compilation.base_allocator, type_data);
|
||||
_ = try module.types.array.append(compilation.base_allocator, type_data);
|
||||
}
|
||||
semantic_analyzer.pointer_to_any_type = (try module.types.append(compilation.base_allocator, .{
|
||||
semantic_analyzer.pointer_to_any_type = try module.types.array.append(compilation.base_allocator, .{
|
||||
.pointer = .{
|
||||
.element_type = Type.any,
|
||||
.many = false,
|
||||
.@"const" = true,
|
||||
},
|
||||
})).index;
|
||||
semantic_analyzer.optional_pointer_to_any_type = (try module.types.append(compilation.base_allocator, .{
|
||||
});
|
||||
semantic_analyzer.optional_pointer_to_any_type = try module.types.array.append(compilation.base_allocator, .{
|
||||
.optional = .{
|
||||
.element_type = semantic_analyzer.pointer_to_any_type,
|
||||
},
|
||||
})).index;
|
||||
semantic_analyzer.optional_any = (try module.types.append(compilation.base_allocator, .{
|
||||
});
|
||||
semantic_analyzer.optional_any = try module.types.array.append(compilation.base_allocator, .{
|
||||
.optional = .{
|
||||
.element_type = Type.any,
|
||||
},
|
||||
})).index;
|
||||
});
|
||||
|
||||
semantic_analyzer.unreachable_index = (try module.values.append(compilation.base_allocator, .@"unreachable")).index;
|
||||
semantic_analyzer.pointer_null_index = (try module.values.append(compilation.base_allocator, .pointer_null_literal)).index;
|
||||
semantic_analyzer.optional_null_index = (try module.values.append(compilation.base_allocator, .optional_null_literal)).index;
|
||||
semantic_analyzer.unreachable_index = try module.values.array.append(compilation.base_allocator, .@"unreachable");
|
||||
semantic_analyzer.pointer_null_index = try module.values.array.append(compilation.base_allocator, .pointer_null_literal);
|
||||
semantic_analyzer.optional_null_index = try module.values.array.append(compilation.base_allocator, .optional_null_literal);
|
||||
semantic_analyzer.undefined_index = try module.values.array.append(compilation.base_allocator, .undefined);
|
||||
|
||||
const value_allocation = try module.values.append(compilation.base_allocator, .{
|
||||
const value_index = try module.values.array.append(compilation.base_allocator, .{
|
||||
.unresolved = .{
|
||||
.node_index = .{ .value = 0 },
|
||||
},
|
||||
});
|
||||
|
||||
try semantic_analyzer.initialize(compilation, module, packages[0], value_allocation.ptr);
|
||||
try semantic_analyzer.initialize(compilation, module, packages[0], value_index);
|
||||
|
||||
if (descriptor.transpile_to_c) {
|
||||
try c_transpiler.initialize(compilation, module, descriptor);
|
||||
@ -1355,8 +1302,6 @@ const LoggerScope = enum {
|
||||
lexer,
|
||||
parser,
|
||||
sema,
|
||||
ir,
|
||||
codegen,
|
||||
c,
|
||||
};
|
||||
|
||||
@ -1374,8 +1319,6 @@ fn getLoggerScopeType(comptime logger_scope: LoggerScope) type {
|
||||
.lexer => lexical_analyzer,
|
||||
.parser => syntactic_analyzer,
|
||||
.sema => semantic_analyzer,
|
||||
.ir => intermediate_representation,
|
||||
.codegen => emit,
|
||||
.c => c_transpiler,
|
||||
};
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ pub const TranslationUnit = struct {
|
||||
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) = .{},
|
||||
declaration_set: AutoArrayHashMap(Compilation.Declaration.Index, []const u8) = .{},
|
||||
|
||||
const SyscallBitset = std.StaticBitSet(6);
|
||||
@ -65,7 +66,7 @@ pub const TranslationUnit = struct {
|
||||
);
|
||||
|
||||
{
|
||||
var function_definitions = module.function_definitions.iterator();
|
||||
var function_definitions = module.types.function_definitions.iterator();
|
||||
while (function_definitions.nextIndex()) |function_definition_index| {
|
||||
_ = try unit.writeFunctionDefinition(module, allocator, function_definition_index);
|
||||
}
|
||||
@ -78,9 +79,9 @@ pub const TranslationUnit = struct {
|
||||
const gop = try unit.function_set.getOrPut(allocator, function_definition_index);
|
||||
|
||||
if (!gop.found_existing) {
|
||||
const function_definition = module.function_definitions.get(function_definition_index);
|
||||
const function_definition = module.types.function_definitions.get(function_definition_index);
|
||||
const function_prototype_type = function_definition.prototype;
|
||||
const function_prototype = module.function_prototypes.get(module.types.get(function_prototype_type).function);
|
||||
const function_prototype = module.types.function_prototypes.get(module.types.array.get(function_prototype_type).function);
|
||||
|
||||
const function_name = try unit.writeFunctionHeader(module, &unit.function_declarations, allocator, function_definition_index);
|
||||
gop.value_ptr.* = function_name;
|
||||
@ -97,13 +98,13 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
fn writeDeclaration(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, declaration_index: Compilation.Declaration.Index, indentation: usize) !void {
|
||||
const declaration = module.declarations.get(declaration_index);
|
||||
const declaration = module.values.declarations.get(declaration_index);
|
||||
const mangle = false;
|
||||
const name = try unit.renderDeclarationName(module, allocator, declaration_index, mangle);
|
||||
|
||||
if (declaration.mutability == .@"const") {
|
||||
switch (module.types.get(declaration.type).*) {
|
||||
.optional => |optional| switch (module.types.get(optional.element_type).*) {
|
||||
switch (module.types.array.get(declaration.type).*) {
|
||||
.optional => |optional| switch (module.types.array.get(optional.element_type).*) {
|
||||
.pointer => {},
|
||||
else => try list.appendSlice(allocator, "const "),
|
||||
},
|
||||
@ -133,8 +134,8 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
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 {
|
||||
const assignment = module.assignments.get(assignment_index);
|
||||
const left_type = module.values.get(assignment.source).getType(module);
|
||||
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, .{
|
||||
.value_index = assignment.destination,
|
||||
.type_index = left_type,
|
||||
@ -153,14 +154,14 @@ pub const TranslationUnit = struct {
|
||||
|
||||
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 {
|
||||
try list.appendSlice(allocator, "{\n");
|
||||
const block = module.blocks.get(block_index);
|
||||
const block = module.values.blocks.get(block_index);
|
||||
|
||||
const indentation = old_indentation + 1;
|
||||
|
||||
for (block.statements.items) |statement_index| {
|
||||
try list.appendNTimes(allocator, ' ', indentation * margin_width);
|
||||
|
||||
const statement = module.values.get(statement_index);
|
||||
const statement = module.values.array.get(statement_index);
|
||||
switch (statement.*) {
|
||||
.declaration => |declaration_index| {
|
||||
try unit.writeDeclaration(module, list, allocator, declaration_index, indentation);
|
||||
@ -171,13 +172,13 @@ pub const TranslationUnit = struct {
|
||||
try list.append(allocator, ';');
|
||||
},
|
||||
.@"return" => |return_index| {
|
||||
const return_expr = module.returns.get(return_index);
|
||||
const return_expr = module.values.returns.get(return_index);
|
||||
try list.appendSlice(allocator, "return ");
|
||||
const return_value = module.values.get(return_expr.value);
|
||||
const return_value = module.values.array.get(return_expr.value);
|
||||
const return_value_type_index = return_value.getType(module);
|
||||
// _ = return_value_type_index;
|
||||
switch (module.types.get(function_return_type).*) {
|
||||
.optional => switch (module.types.get(return_value_type_index).*) {
|
||||
switch (module.types.array.get(function_return_type).*) {
|
||||
.optional => switch (module.types.array.get(return_value_type_index).*) {
|
||||
.optional => try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = return_expr.value,
|
||||
.type_index = function_return_type,
|
||||
@ -221,7 +222,7 @@ pub const TranslationUnit = struct {
|
||||
try list.append(allocator, ';');
|
||||
},
|
||||
.branch => |branch_index| {
|
||||
const branch = module.branches.get(branch_index);
|
||||
const branch = module.values.branches.get(branch_index);
|
||||
try list.appendSlice(allocator, "if (");
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = branch.expression,
|
||||
@ -234,7 +235,7 @@ pub const TranslationUnit = struct {
|
||||
});
|
||||
|
||||
if (!branch.not_taken_expression.invalid) {
|
||||
if (module.values.get(branch.taken_expression).* == .block) {
|
||||
if (module.values.array.get(branch.taken_expression).* == .block) {
|
||||
_ = list.pop();
|
||||
try list.appendSlice(allocator, " else ");
|
||||
} else {
|
||||
@ -245,7 +246,7 @@ pub const TranslationUnit = struct {
|
||||
.type_index = function_return_type,
|
||||
});
|
||||
|
||||
if (module.values.get(branch.not_taken_expression).* == .block) {
|
||||
if (module.values.array.get(branch.not_taken_expression).* == .block) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -255,7 +256,7 @@ pub const TranslationUnit = struct {
|
||||
try list.append(allocator, ';');
|
||||
},
|
||||
.loop => |loop_index| {
|
||||
const loop = module.loops.get(loop_index);
|
||||
const loop = module.values.loops.get(loop_index);
|
||||
try list.appendSlice(allocator, "for (");
|
||||
if (!loop.pre.invalid) {
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
@ -286,6 +287,9 @@ pub const TranslationUnit = struct {
|
||||
.type_index = Compilation.Type.Index.invalid,
|
||||
});
|
||||
},
|
||||
.block => |new_block_index| {
|
||||
try unit.writeBlock(module, list, allocator, new_block_index, function_return_type, indentation);
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
||||
@ -302,19 +306,19 @@ pub const TranslationUnit = struct {
|
||||
};
|
||||
|
||||
fn renderTypeName(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 {
|
||||
const declaration_index = module.type_map.get(type_index).?;
|
||||
const declaration_index = module.map.types.get(type_index).?;
|
||||
const mangle = true;
|
||||
const result = try unit.renderDeclarationName(module, allocator, declaration_index, mangle);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn renderFunctionName(unit: *TranslationUnit, module: *Module, allocator: Allocator, function_index: Compilation.Function.Index) ![]const u8 {
|
||||
const function_definition = module.function_definitions.get(function_index);
|
||||
const function_prototype_type = module.types.get(function_definition.prototype);
|
||||
const function_definition = module.types.function_definitions.get(function_index);
|
||||
const function_prototype_type = module.types.array.get(function_definition.prototype);
|
||||
const function_prototype_index = function_prototype_type.function;
|
||||
const function_prototype = module.function_prototypes.get(function_prototype_index);
|
||||
const function_prototype = module.types.function_prototypes.get(function_prototype_index);
|
||||
const mangle = !(function_prototype.attributes.@"export" or function_prototype.attributes.@"extern");
|
||||
const function_declaration_index = module.function_map.get(function_index).?;
|
||||
const function_declaration_index = module.map.functions.get(function_index).?;
|
||||
const name = try unit.renderDeclarationName(module, allocator, function_declaration_index, mangle);
|
||||
return name;
|
||||
}
|
||||
@ -323,7 +327,7 @@ pub const TranslationUnit = struct {
|
||||
const gop = try unit.declaration_set.getOrPut(allocator, declaration_index);
|
||||
|
||||
if (!gop.found_existing) {
|
||||
const declaration = module.declarations.get(declaration_index);
|
||||
const declaration = module.values.declarations.get(declaration_index);
|
||||
const base_declaration_name = module.getName(declaration.name).?;
|
||||
var list = ArrayList(u8){};
|
||||
|
||||
@ -336,10 +340,10 @@ pub const TranslationUnit = struct {
|
||||
switch (declaration.scope_type) {
|
||||
.global => {
|
||||
while (!scope_index.invalid) {
|
||||
const scope = module.scopes.get(scope_index);
|
||||
const scope = module.values.scopes.get(scope_index);
|
||||
|
||||
if (module.type_map.get(scope.type)) |type_declaration| {
|
||||
const scope_type_declaration = module.declarations.get(type_declaration);
|
||||
if (module.map.types.get(scope.type)) |type_declaration| {
|
||||
const scope_type_declaration = module.values.declarations.get(type_declaration);
|
||||
const scope_type_declaration_name = module.getName(scope_type_declaration.name).?;
|
||||
try list.insert(allocator, 0, '_');
|
||||
try list.insertSlice(allocator, 0, scope_type_declaration_name);
|
||||
@ -361,7 +365,7 @@ pub const TranslationUnit = struct {
|
||||
gop.value_ptr.* = list.items;
|
||||
|
||||
switch (declaration.scope_type) {
|
||||
.global => switch (module.types.get(declaration.type).*) {
|
||||
.global => switch (module.types.array.get(declaration.type).*) {
|
||||
.function,
|
||||
.type,
|
||||
=> {},
|
||||
@ -383,7 +387,7 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
fn writeFunctionPrototype(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function_prototype_index: Compilation.Function.Prototype.Index, name: []const u8) !void {
|
||||
const function_prototype = module.function_prototypes.get(function_prototype_index);
|
||||
const function_prototype = module.types.function_prototypes.get(function_prototype_index);
|
||||
switch (function_prototype.attributes.calling_convention) {
|
||||
.system_v => {},
|
||||
.naked => try list.appendSlice(allocator, "[[gnu::naked]] "),
|
||||
@ -399,7 +403,7 @@ pub const TranslationUnit = struct {
|
||||
|
||||
if (function_prototype.arguments) |function_arguments| {
|
||||
for (function_arguments) |argument_index| {
|
||||
const arg_declaration = module.declarations.get(argument_index);
|
||||
const arg_declaration = module.values.declarations.get(argument_index);
|
||||
try unit.writeType(module, list, allocator, arg_declaration.type);
|
||||
try list.append(allocator, ' ');
|
||||
const arg_name = module.getName(arg_declaration.name).?;
|
||||
@ -415,8 +419,8 @@ pub const TranslationUnit = struct {
|
||||
|
||||
fn writeFunctionHeader(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function_index: Compilation.Function.Index) ![]const u8 {
|
||||
const name = try unit.renderFunctionName(module, allocator, function_index);
|
||||
const function_definition = module.function_definitions.get(function_index);
|
||||
const function_prototype_type = module.types.get(function_definition.prototype);
|
||||
const function_definition = module.types.function_definitions.get(function_index);
|
||||
const function_prototype_type = module.types.array.get(function_definition.prototype);
|
||||
const function_prototype_index = function_prototype_type.function;
|
||||
try unit.writeFunctionPrototype(module, list, allocator, function_prototype_index, name);
|
||||
|
||||
@ -424,7 +428,7 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
fn writeType(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, type_index: Compilation.Type.Index) anyerror!void {
|
||||
const sema_type = module.types.get(type_index);
|
||||
const sema_type = module.types.array.get(type_index);
|
||||
|
||||
switch (sema_type.*) {
|
||||
.void => try list.appendSlice(allocator, "void"),
|
||||
@ -438,7 +442,7 @@ pub const TranslationUnit = struct {
|
||||
try list.writer(allocator).print("{}", .{integer.bit_count});
|
||||
},
|
||||
.pointer => |pointer| {
|
||||
switch (module.types.get(pointer.element_type).*) {
|
||||
switch (module.types.array.get(pointer.element_type).*) {
|
||||
.function => {
|
||||
@panic("This should be unreachable");
|
||||
},
|
||||
@ -463,16 +467,20 @@ pub const TranslationUnit = struct {
|
||||
const name = try unit.cacheSliceType(module, allocator, type_index);
|
||||
try list.appendSlice(allocator, name);
|
||||
},
|
||||
.array => {
|
||||
const name = try unit.cacheArrayType(module, allocator, type_index);
|
||||
try list.appendSlice(allocator, name);
|
||||
},
|
||||
.any => @panic("Internal compiler error: 'any' made it to the backend"),
|
||||
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 {
|
||||
const declaration_type = module.types.get(type_index);
|
||||
const declaration_type = module.types.array.get(type_index);
|
||||
switch (declaration_type.*) {
|
||||
.pointer => |pointer| {
|
||||
switch (module.types.get(pointer.element_type).*) {
|
||||
switch (module.types.array.get(pointer.element_type).*) {
|
||||
.function => |function| return try unit.writeFunctionPrototype(module, list, allocator, function, try std.mem.concat(allocator, u8, &.{ "(*", name, ")" })),
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
@ -486,10 +494,10 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
fn writeAssembly(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, assembly_block_index: Compilation.Assembly.Block.Index, indentation: usize) !void {
|
||||
const assembly_block = module.assembly_blocks.get(assembly_block_index);
|
||||
const assembly_block = module.values.assembly_blocks.get(assembly_block_index);
|
||||
try list.appendSlice(allocator, "__asm__ __volatile__(\n");
|
||||
for (assembly_block.instructions) |instruction_index| {
|
||||
const generic_instruction = module.assembly_instructions.get(instruction_index);
|
||||
const generic_instruction = module.values.assembly_instructions.get(instruction_index);
|
||||
try list.appendNTimes(allocator, ' ', (indentation + 1) * margin_width);
|
||||
try list.append(allocator, '"');
|
||||
switch (module.descriptor.target.cpu.arch) {
|
||||
@ -547,12 +555,12 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
fn cacheStructType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 {
|
||||
const t = module.types.get(type_index);
|
||||
const t = module.types.array.get(type_index);
|
||||
assert(t.* == .@"struct");
|
||||
const gop = try unit.struct_type_set.getOrPut(allocator, type_index);
|
||||
|
||||
if (!gop.found_existing) {
|
||||
const struct_type = module.structs.get(t.@"struct");
|
||||
const struct_type = module.types.structs.get(t.@"struct");
|
||||
const type_name = try unit.renderTypeName(module, allocator, type_index);
|
||||
gop.value_ptr.* = type_name;
|
||||
// Forward declare the struct
|
||||
@ -573,7 +581,7 @@ pub const TranslationUnit = struct {
|
||||
for (struct_type.fields.items) |struct_field_index| {
|
||||
try unit.type_declarations.appendNTimes(allocator, ' ', margin_width);
|
||||
|
||||
const struct_field = module.container_fields.get(struct_field_index);
|
||||
const struct_field = module.types.container_fields.get(struct_field_index);
|
||||
const struct_field_name = module.getName(struct_field.name).?;
|
||||
|
||||
switch (struct_type.backing_type.invalid) {
|
||||
@ -582,7 +590,7 @@ pub const TranslationUnit = struct {
|
||||
try unit.type_declarations.append(allocator, ' ');
|
||||
try unit.type_declarations.appendSlice(allocator, struct_field_name);
|
||||
try unit.type_declarations.appendSlice(allocator, " : ");
|
||||
try unit.type_declarations.writer(allocator).print("{}", .{module.types.get(struct_field.type).getBitSize()});
|
||||
try unit.type_declarations.writer(allocator).print("{}", .{module.types.array.get(struct_field.type).getBitSize()});
|
||||
},
|
||||
true => try unit.writeCDeclaration(module, &unit.type_declarations, allocator, struct_field_name, struct_field.type),
|
||||
}
|
||||
@ -602,7 +610,7 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
fn cacheOptionalType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 {
|
||||
const optional_type = module.types.get(type_index);
|
||||
const optional_type = module.types.array.get(type_index);
|
||||
assert(optional_type.* == .optional);
|
||||
const optional = optional_type.optional;
|
||||
|
||||
@ -610,7 +618,7 @@ pub const TranslationUnit = struct {
|
||||
|
||||
if (!gop.found_existing) {
|
||||
var type_name = ArrayList(u8){};
|
||||
const optional_element_type = module.types.get(optional.element_type);
|
||||
const optional_element_type = module.types.array.get(optional.element_type);
|
||||
|
||||
switch (optional_element_type.*) {
|
||||
.pointer => {
|
||||
@ -652,7 +660,7 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
fn cacheSliceType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 {
|
||||
const slice = module.types.get(type_index).slice;
|
||||
const slice = module.types.array.get(type_index).slice;
|
||||
|
||||
const gop = try unit.slice_type_set.getOrPut(allocator, slice.element_type);
|
||||
|
||||
@ -687,8 +695,44 @@ pub const TranslationUnit = struct {
|
||||
return gop.value_ptr.*;
|
||||
}
|
||||
|
||||
fn cacheArrayType(unit: *TranslationUnit, module: *Module, allocator: Allocator, type_index: Compilation.Type.Index) ![]const u8 {
|
||||
const array = module.types.array.get(type_index).array;
|
||||
|
||||
const gop = try unit.array_type_set.getOrPut(allocator, array.element_type);
|
||||
|
||||
if (!gop.found_existing) {
|
||||
var type_name = ArrayList(u8){};
|
||||
try type_name.appendSlice(allocator, "Array_");
|
||||
try unit.writeType(module, &type_name, allocator, array.element_type);
|
||||
try type_name.writer(allocator).print("_{}", .{array.element_count});
|
||||
gop.value_ptr.* = type_name.items;
|
||||
|
||||
try unit.type_forward_declarations.appendSlice(allocator, "typedef struct ");
|
||||
try unit.type_forward_declarations.appendSlice(allocator, type_name.items);
|
||||
try unit.type_forward_declarations.append(allocator, ' ');
|
||||
try unit.type_forward_declarations.appendSlice(allocator, type_name.items);
|
||||
try unit.type_forward_declarations.appendSlice(allocator, ";\n");
|
||||
|
||||
try unit.type_declarations.appendSlice(allocator, "typedef struct ");
|
||||
try unit.type_declarations.appendSlice(allocator, type_name.items);
|
||||
try unit.type_declarations.appendSlice(allocator, " {\n");
|
||||
|
||||
try unit.type_declarations.appendNTimes(allocator, ' ', margin_width);
|
||||
try unit.writeType(module, &unit.type_declarations, allocator, array.element_type);
|
||||
try unit.type_declarations.appendSlice(allocator, " value\n");
|
||||
|
||||
try unit.type_declarations.writer(allocator).print("[{}];\n", .{array.element_count});
|
||||
|
||||
try unit.type_declarations.appendSlice(allocator, "} ");
|
||||
try unit.type_declarations.appendSlice(allocator, type_name.items);
|
||||
try unit.type_declarations.appendSlice(allocator, ";\n\n");
|
||||
}
|
||||
|
||||
return gop.value_ptr.*;
|
||||
}
|
||||
|
||||
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 {
|
||||
const syscall = module.syscalls.get(syscall_index);
|
||||
const syscall = module.values.syscalls.get(syscall_index);
|
||||
const arguments = syscall.getArguments();
|
||||
|
||||
if (!unit.syscall_bitset.isSet(arguments.len - 1)) {
|
||||
@ -774,8 +818,8 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
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 {
|
||||
const call = module.calls.get(call_index);
|
||||
const call_value = module.values.get(call.value);
|
||||
const call = module.values.calls.get(call_index);
|
||||
const call_value = module.values.array.get(call.value);
|
||||
switch (call_value.*) {
|
||||
.function_definition => |function_definition_index| {
|
||||
const name = try unit.renderFunctionName(module, allocator, function_definition_index);
|
||||
@ -783,13 +827,13 @@ pub const TranslationUnit = struct {
|
||||
try list.append(allocator, '(');
|
||||
},
|
||||
.field_access => |field_access_index| {
|
||||
const field_access = module.field_accesses.get(field_access_index);
|
||||
const field_access = module.values.field_accesses.get(field_access_index);
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = field_access.declaration_reference,
|
||||
.type_index = function_return_type,
|
||||
});
|
||||
|
||||
const left_type = module.types.get(module.values.get(field_access.declaration_reference).declaration_reference.type);
|
||||
const left_type = module.types.array.get(module.values.array.get(field_access.declaration_reference).declaration_reference.type);
|
||||
const is_pointer = switch (left_type.*) {
|
||||
.pointer => true,
|
||||
else => false,
|
||||
@ -801,7 +845,7 @@ pub const TranslationUnit = struct {
|
||||
try list.append(allocator, '.');
|
||||
}
|
||||
|
||||
const field = module.container_fields.get(field_access.field);
|
||||
const field = module.types.container_fields.get(field_access.field);
|
||||
const field_name = module.getName(field.name).?;
|
||||
try list.appendSlice(allocator, field_name);
|
||||
try list.append(allocator, '(');
|
||||
@ -810,7 +854,7 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
|
||||
if (!call.arguments.invalid) {
|
||||
const argument_list = module.argument_lists.get(call.arguments);
|
||||
const argument_list = module.values.argument_lists.get(call.arguments);
|
||||
|
||||
if (argument_list.array.items.len > 0) {
|
||||
for (argument_list.array.items) |argument_index| {
|
||||
@ -838,7 +882,7 @@ pub const TranslationUnit = struct {
|
||||
const value_index = arguments.value_index;
|
||||
const type_index = arguments.type_index;
|
||||
_ = type_index;
|
||||
const value = module.values.get(value_index);
|
||||
const value = module.values.array.get(value_index);
|
||||
switch (value.*) {
|
||||
.declaration => |declaration_index| {
|
||||
try unit.writeDeclaration(module, list, allocator, declaration_index, indentation);
|
||||
@ -855,7 +899,7 @@ pub const TranslationUnit = struct {
|
||||
try list.appendSlice(allocator, name);
|
||||
},
|
||||
.binary_operation => |binary_operation_index| {
|
||||
const binary_operation = module.binary_operations.get(binary_operation_index);
|
||||
const binary_operation = module.values.binary_operations.get(binary_operation_index);
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = binary_operation.left,
|
||||
.type_index = binary_operation.type,
|
||||
@ -886,23 +930,23 @@ pub const TranslationUnit = struct {
|
||||
});
|
||||
},
|
||||
.sign_extend => |cast_index| {
|
||||
const sign_extend = module.casts.get(cast_index);
|
||||
const sign_extend = module.values.casts.get(cast_index);
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = sign_extend.value,
|
||||
.type_index = sign_extend.type,
|
||||
});
|
||||
},
|
||||
.cast => |cast_index| {
|
||||
const cast = module.casts.get(cast_index);
|
||||
const cast = module.values.casts.get(cast_index);
|
||||
try list.append(allocator, '(');
|
||||
try unit.writeType(module, list, allocator, cast.type);
|
||||
try list.append(allocator, ')');
|
||||
const cast_value = module.values.get(cast.value);
|
||||
const cast_value_type = module.types.get(cast_value.getType(module));
|
||||
const cast_value = module.values.array.get(cast.value);
|
||||
const cast_value_type = module.types.array.get(cast_value.getType(module));
|
||||
|
||||
switch (cast_value_type.*) {
|
||||
.@"struct" => |struct_index| {
|
||||
const struct_type = module.structs.get(struct_index);
|
||||
const struct_type = module.types.structs.get(struct_index);
|
||||
switch (struct_type.backing_type.invalid) {
|
||||
false => {
|
||||
try list.appendSlice(allocator, "*(");
|
||||
@ -923,9 +967,9 @@ pub const TranslationUnit = struct {
|
||||
}),
|
||||
}
|
||||
},
|
||||
.string_literal => |string_literal_hash| {
|
||||
.string_literal => |string_literal_descriptor| {
|
||||
try list.appendSlice(allocator, "(const u8*)");
|
||||
const string_literal = module.string_literals.getValue(string_literal_hash).?;
|
||||
const string_literal = module.getName(string_literal_descriptor.hash) orelse unreachable;
|
||||
try list.append(allocator, '"');
|
||||
try list.appendSlice(allocator, string_literal);
|
||||
try list.append(allocator, '"');
|
||||
@ -938,7 +982,7 @@ pub const TranslationUnit = struct {
|
||||
.bool => |boolean| try list.appendSlice(allocator, if (boolean) "true" else "false"),
|
||||
.block => |block_index| try unit.writeBlock(module, list, allocator, block_index, function_return_type, indentation),
|
||||
.unary_operation => |unary_operation_index| {
|
||||
const unary_operation = module.unary_operations.get(unary_operation_index);
|
||||
const unary_operation = module.values.unary_operations.get(unary_operation_index);
|
||||
const expression_character: u8 = switch (unary_operation.id) {
|
||||
.boolean_not => '!',
|
||||
.negation => '-',
|
||||
@ -955,21 +999,21 @@ pub const TranslationUnit = struct {
|
||||
try list.append(allocator, ')');
|
||||
},
|
||||
.container_initialization => |container_initialization_index| {
|
||||
const container_initialization = module.container_initializations.get(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 list.appendSlice(allocator, ") {\n");
|
||||
|
||||
const container_type = module.types.get(container_initialization.type);
|
||||
const container_type = module.types.array.get(container_initialization.type);
|
||||
const container_fields = switch (container_type.*) {
|
||||
.@"struct" => module.structs.get(container_type.@"struct").fields,
|
||||
.@"struct" => module.types.structs.get(container_type.@"struct").fields,
|
||||
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.container_fields.get(container_field_index);
|
||||
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, " = ");
|
||||
@ -984,10 +1028,10 @@ pub const TranslationUnit = struct {
|
||||
try list.append(allocator, '}');
|
||||
},
|
||||
.field_access => |field_access_index| {
|
||||
const field_access = module.field_accesses.get(field_access_index);
|
||||
const left = module.values.get(field_access.declaration_reference);
|
||||
const left_type = module.types.get(left.getType(module));
|
||||
const right_field = module.container_fields.get(field_access.field);
|
||||
const field_access = module.values.field_accesses.get(field_access_index);
|
||||
const left = module.values.array.get(field_access.declaration_reference);
|
||||
const left_type = module.types.array.get(left.getType(module));
|
||||
const right_field = module.types.container_fields.get(field_access.field);
|
||||
const right_field_name = module.getName(right_field.name).?;
|
||||
const is_pointer = switch (left_type.*) {
|
||||
.@"struct" => false,
|
||||
@ -1015,16 +1059,17 @@ pub const TranslationUnit = struct {
|
||||
try list.appendSlice(allocator, ") { .is_null = true }");
|
||||
},
|
||||
.slice => |slice_index| {
|
||||
const slice = module.slices.get(slice_index);
|
||||
const sliceable = module.values.get(slice.sliceable);
|
||||
const slice = module.values.slices.get(slice_index);
|
||||
const sliceable = module.values.array.get(slice.sliceable);
|
||||
|
||||
const sliceable_type_index = switch (sliceable.*) {
|
||||
.declaration_reference => |declaration_reference| declaration_reference.type,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
const sliceable_type = module.types.get(sliceable_type_index);
|
||||
const sliceable_type = module.types.array.get(sliceable_type_index);
|
||||
const sliceable_element_type = switch (sliceable_type.*) {
|
||||
.pointer => |pointer| pointer.element_type,
|
||||
.slice => |slice_type| slice_type.element_type,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
@ -1049,6 +1094,19 @@ pub const TranslationUnit = struct {
|
||||
});
|
||||
try list.appendSlice(allocator, "),\n");
|
||||
},
|
||||
.slice => {
|
||||
try list.append(allocator, '(');
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{
|
||||
.value_index = slice.sliceable,
|
||||
.type_index = sliceable_type_index,
|
||||
});
|
||||
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,
|
||||
});
|
||||
try list.appendSlice(allocator, "),\n");
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
||||
@ -1076,6 +1134,26 @@ pub const TranslationUnit = struct {
|
||||
},
|
||||
}
|
||||
},
|
||||
.slice => {
|
||||
switch (slice.range.end.invalid) {
|
||||
false => {
|
||||
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,
|
||||
});
|
||||
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,
|
||||
});
|
||||
try list.appendSlice(allocator, ")\n");
|
||||
},
|
||||
true => {
|
||||
unreachable;
|
||||
},
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
||||
@ -1087,10 +1165,10 @@ pub const TranslationUnit = struct {
|
||||
try list.appendSlice(allocator, function_name);
|
||||
},
|
||||
.optional_check => |optional_check_index| {
|
||||
const optional_check = module.optional_checks.get(optional_check_index);
|
||||
const optional_type = module.types.get(module.values.get(optional_check.value).getType(module));
|
||||
const optional_check = module.values.optional_checks.get(optional_check_index);
|
||||
const optional_type = module.types.array.get(module.values.array.get(optional_check.value).getType(module));
|
||||
assert(optional_type.* == .optional);
|
||||
const optional_element_type = module.types.get(optional_type.optional.element_type);
|
||||
const optional_element_type = module.types.array.get(optional_type.optional.element_type);
|
||||
const is_null_suffix_expression = switch (optional_element_type.*) {
|
||||
.pointer => false,
|
||||
else => true,
|
||||
@ -1111,12 +1189,12 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
},
|
||||
.optional_unwrap => |optional_unwrap_index| {
|
||||
const optional_unwrap = module.optional_unwraps.get(optional_unwrap_index);
|
||||
const optional_value = module.values.get(optional_unwrap.value);
|
||||
const optional_type = module.types.get(optional_value.getType(module));
|
||||
const optional_unwrap = module.values.optional_unwraps.get(optional_unwrap_index);
|
||||
const optional_value = module.values.array.get(optional_unwrap.value);
|
||||
const optional_type = module.types.array.get(optional_value.getType(module));
|
||||
assert(optional_type.* == .optional);
|
||||
const optional_element_type_index = optional_type.optional.element_type;
|
||||
const optional_element_type = module.types.get(optional_element_type_index);
|
||||
const optional_element_type = module.types.array.get(optional_element_type_index);
|
||||
|
||||
try list.append(allocator, '(');
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
@ -1131,7 +1209,7 @@ pub const TranslationUnit = struct {
|
||||
}
|
||||
},
|
||||
.slice_access => |slice_access_index| {
|
||||
const slice_access = module.slice_accesses.get(slice_access_index);
|
||||
const slice_access = module.values.slice_accesses.get(slice_access_index);
|
||||
try list.append(allocator, '(');
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = slice_access.value,
|
||||
@ -1141,17 +1219,17 @@ pub const TranslationUnit = struct {
|
||||
try list.appendSlice(allocator, @tagName(slice_access.field));
|
||||
},
|
||||
.indexed_access => |indexed_access_index| {
|
||||
const indexed_access = module.indexed_accesses.get(indexed_access_index);
|
||||
const indexed_access = module.values.indexed_accesses.get(indexed_access_index);
|
||||
try list.append(allocator, '(');
|
||||
const indexed_expression_index = indexed_access.indexed_expression;
|
||||
const indexed_expression = module.values.get(indexed_expression_index);
|
||||
const indexed_expression = module.values.array.get(indexed_expression_index);
|
||||
const indexed_expression_type_index = indexed_expression.getType(module);
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = indexed_expression_index,
|
||||
.type_index = indexed_expression_type_index,
|
||||
});
|
||||
|
||||
const indexed_expression_type = module.types.get(indexed_expression_type_index);
|
||||
const indexed_expression_type = module.types.array.get(indexed_expression_type_index);
|
||||
switch (indexed_expression_type.*) {
|
||||
.slice => {
|
||||
try list.appendSlice(allocator, ".ptr");
|
||||
@ -1166,6 +1244,62 @@ pub const TranslationUnit = struct {
|
||||
});
|
||||
try list.append(allocator, ']');
|
||||
},
|
||||
.optional_cast => |cast_index| {
|
||||
const optional_cast = module.values.casts.get(cast_index);
|
||||
const optional_type = module.types.array.get(optional_cast.type);
|
||||
switch (optional_type.*) {
|
||||
.optional => |optional| {
|
||||
const optional_element_type = module.types.array.get(optional.element_type);
|
||||
switch (optional_element_type.*) {
|
||||
.pointer => try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = optional_cast.value,
|
||||
.type_index = optional.element_type,
|
||||
}),
|
||||
else => {
|
||||
try list.append(allocator, '(');
|
||||
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,
|
||||
});
|
||||
try list.appendSlice(allocator, ",\n");
|
||||
try list.appendNTimes(allocator, ' ', indentation * margin_width);
|
||||
try list.appendSlice(allocator, ".is_null = false,\n");
|
||||
try list.appendNTimes(allocator, ' ', indentation * margin_width);
|
||||
try list.append(allocator, '}');
|
||||
},
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
},
|
||||
.undefined => try list.appendSlice(allocator, "{}"),
|
||||
.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 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,
|
||||
});
|
||||
try list.appendSlice(allocator, ".value,\n");
|
||||
try list.appendNTimes(allocator, ' ', indentation * margin_width);
|
||||
const array_value = module.values.array.get(array_coerce_to_slice.value);
|
||||
const array_type = module.types.array.get(array_value.getType(module));
|
||||
const array_length = switch (array_type.*) {
|
||||
.array => |array| array.element_count,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
try list.writer(allocator).print(".len = {},\n", .{array_length});
|
||||
try list.appendNTimes(allocator, ' ', indentation * margin_width);
|
||||
try list.append(allocator, '}');
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
}
|
||||
|
@ -1,394 +0,0 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const equal = std.mem.eql;
|
||||
|
||||
const data_structures = @import("../data_structures.zig");
|
||||
const Allocator = data_structures.Allocator;
|
||||
const ArrayList = data_structures.ArrayList;
|
||||
|
||||
const emit = @import("emit.zig");
|
||||
const page_size = 0x1000;
|
||||
|
||||
pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, page_size) {
|
||||
const allocator = image.section_manager.allocator;
|
||||
|
||||
try image.section_manager.addNullSection();
|
||||
|
||||
const symbol_table_index = try image.section_manager.addSection(.{
|
||||
.name = ".symtab",
|
||||
.size_guess = 50,
|
||||
.alignment = @alignOf(SymbolTable.Entry),
|
||||
.flags = .{
|
||||
.read = false,
|
||||
.write = false,
|
||||
.execute = false,
|
||||
},
|
||||
.type = .symbol_table,
|
||||
});
|
||||
const string_table_index = try image.section_manager.addSection(.{
|
||||
.name = ".strtab",
|
||||
.size_guess = 50,
|
||||
.alignment = 1,
|
||||
.flags = .{
|
||||
.read = false,
|
||||
.write = false,
|
||||
.execute = false,
|
||||
},
|
||||
.type = .string_table,
|
||||
});
|
||||
const section_header_string_table_index = try image.section_manager.addSection(.{
|
||||
.name = ".shstrtab",
|
||||
.size_guess = 50,
|
||||
.alignment = 1,
|
||||
.flags = .{
|
||||
.read = false,
|
||||
.write = false,
|
||||
.execute = false,
|
||||
},
|
||||
.type = .string_table,
|
||||
});
|
||||
|
||||
const base_virtual_address = 0x400000;
|
||||
const text_section_index = 1;
|
||||
|
||||
const program_header_count = blk: {
|
||||
var result: usize = 0;
|
||||
for (image.section_manager.sections.items) |section| {
|
||||
result += @intFromBool(switch (section.type) {
|
||||
.null => false,
|
||||
.loadable_program => true,
|
||||
.string_table => false,
|
||||
.symbol_table => false,
|
||||
});
|
||||
}
|
||||
break :blk result;
|
||||
};
|
||||
|
||||
var symbol_name_offset: u32 = 0;
|
||||
|
||||
try image.section_manager.appendToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
|
||||
.name_offset = symbol_name_offset,
|
||||
.information = 0,
|
||||
.other = 0,
|
||||
.section_header_index = 0,
|
||||
.value = 0,
|
||||
.size = 0,
|
||||
}));
|
||||
|
||||
try image.section_manager.appendToSection(string_table_index, "");
|
||||
try image.section_manager.appendByteToSection(string_table_index, 0);
|
||||
symbol_name_offset += 1;
|
||||
|
||||
for (image.section_manager.sections.items) |section| {
|
||||
try image.section_manager.appendToSection(section_header_string_table_index, section.name);
|
||||
try image.section_manager.appendByteToSection(section_header_string_table_index, 0);
|
||||
}
|
||||
|
||||
try image.section_manager.appendToSection(0, std.mem.asBytes(&Header{
|
||||
.endianness = .little,
|
||||
.machine = switch (image.target.cpu.arch) {
|
||||
.x86_64 => .AMD64,
|
||||
else => unreachable,
|
||||
},
|
||||
.os_abi = switch (image.target.os.tag) {
|
||||
.linux => .systemv,
|
||||
else => unreachable,
|
||||
},
|
||||
.entry = 0, // overwritten later
|
||||
.section_header_offset = 0, // overwritten later
|
||||
.program_header_count = @intCast(program_header_count),
|
||||
.section_header_count = @intCast(image.section_manager.sections.items.len),
|
||||
.section_header_string_table_index = @intCast(section_header_string_table_index),
|
||||
}));
|
||||
|
||||
var program_segment_offset: usize = 0;
|
||||
|
||||
for (image.section_manager.sections.items, 0..) |section, section_index| {
|
||||
switch (section.type) {
|
||||
.loadable_program => {
|
||||
program_segment_offset = std.mem.alignForward(usize, program_segment_offset, section.alignment);
|
||||
const virtual_address = base_virtual_address + program_segment_offset;
|
||||
const program_segment_size = switch (section_index) {
|
||||
0 => @sizeOf(Header) + @sizeOf(ProgramHeader) * program_header_count,
|
||||
else => section.bytes.items.len,
|
||||
};
|
||||
|
||||
try image.section_manager.appendToSection(0, std.mem.asBytes(&ProgramHeader{
|
||||
.type = .load,
|
||||
.flags = ProgramHeader.Flags{
|
||||
.executable = section.flags.execute,
|
||||
.writable = section.flags.write,
|
||||
.readable = section.flags.read,
|
||||
},
|
||||
.offset = program_segment_offset,
|
||||
.virtual_address = virtual_address,
|
||||
.physical_address = virtual_address,
|
||||
.size_in_file = program_segment_size,
|
||||
.size_in_memory = program_segment_size,
|
||||
.alignment = section.alignment,
|
||||
}));
|
||||
|
||||
program_segment_offset += program_segment_size;
|
||||
},
|
||||
.null,
|
||||
.string_table,
|
||||
.symbol_table,
|
||||
=> {},
|
||||
}
|
||||
}
|
||||
|
||||
var file = try std.ArrayListAlignedUnmanaged(u8, 0x1000).initCapacity(allocator, 0x100000);
|
||||
var section_headers = try ArrayList(SectionHeader).initCapacity(allocator, image.section_manager.sections.items.len);
|
||||
var section_name_offset: u32 = 0;
|
||||
|
||||
for (image.section_manager.sections.items, 0..) |section, section_i| {
|
||||
const section_offset = std.mem.alignForward(usize, file.items.len, section.alignment);
|
||||
const virtual_address = base_virtual_address + section_offset;
|
||||
|
||||
if (file.items.len < section_offset) {
|
||||
try file.appendNTimes(allocator, 0, section_offset - file.items.len);
|
||||
}
|
||||
|
||||
for (section.symbol_table.keys(), section.symbol_table.values()) |symbol_name, symbol_offset| {
|
||||
const symbol_address = virtual_address + symbol_offset;
|
||||
try image.section_manager.appendToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
|
||||
.name_offset = symbol_name_offset,
|
||||
.information = 0x10,
|
||||
.other = 0,
|
||||
.section_header_index = @intCast(section_i),
|
||||
.value = symbol_address,
|
||||
.size = 0,
|
||||
}));
|
||||
|
||||
try image.section_manager.appendToSection(string_table_index, symbol_name);
|
||||
try image.section_manager.appendByteToSection(string_table_index, 0);
|
||||
|
||||
symbol_name_offset += @intCast(symbol_name.len + 1);
|
||||
}
|
||||
|
||||
try file.appendSlice(image.section_manager.allocator, section.bytes.items);
|
||||
|
||||
section_headers.appendAssumeCapacity(SectionHeader{
|
||||
.name_offset = section_name_offset,
|
||||
.type = switch (section_i) {
|
||||
0 => .null,
|
||||
else => switch (section.type) {
|
||||
.loadable_program => .program_data,
|
||||
.string_table => .string_table,
|
||||
.symbol_table => .symbol_table,
|
||||
.null => .null,
|
||||
},
|
||||
},
|
||||
.flags = .{
|
||||
.alloc = true,
|
||||
.executable = section.flags.execute,
|
||||
.writable = section.flags.write,
|
||||
},
|
||||
.virtual_address = virtual_address,
|
||||
.file_offset = section_offset,
|
||||
.size = section.bytes.items.len,
|
||||
.link = switch (section.type) {
|
||||
.symbol_table => @intCast(string_table_index),
|
||||
else => 0,
|
||||
},
|
||||
.info = switch (section.type) {
|
||||
.symbol_table => 1,
|
||||
else => 0,
|
||||
},
|
||||
.alignment = 0,
|
||||
.entry_size = switch (section.type) {
|
||||
.symbol_table => @sizeOf(SymbolTable.Entry),
|
||||
else => 0,
|
||||
},
|
||||
});
|
||||
|
||||
section_name_offset += @intCast(section.name.len + 1);
|
||||
}
|
||||
|
||||
const section_header_offset = std.mem.alignForward(usize, file.items.len, @alignOf(SectionHeader));
|
||||
const section_header_bytes = std.mem.sliceAsBytes(section_headers.items);
|
||||
|
||||
try file.ensureTotalCapacity(allocator, section_header_offset + section_header_bytes.len);
|
||||
|
||||
if (file.items.len < section_header_offset) {
|
||||
file.appendNTimesAssumeCapacity(0, section_header_offset - file.items.len);
|
||||
}
|
||||
|
||||
file.appendSliceAssumeCapacity(section_header_bytes);
|
||||
|
||||
// At this point, the file array list is not going to grow, so it's safe to practice relocations
|
||||
for (image.section_manager.linker_relocations.items) |relocation| {
|
||||
const source_section_index = relocation.source.index + @intFromBool(image.section_manager.null);
|
||||
const target_section_index = relocation.target.index + @intFromBool(image.section_manager.null);
|
||||
const source_section_header = §ion_headers.items[source_section_index];
|
||||
const target_section_header = §ion_headers.items[target_section_index];
|
||||
const source_file_offset = source_section_header.file_offset + relocation.source.offset;
|
||||
const source_virtual_address = source_section_header.virtual_address + relocation.source.offset;
|
||||
const target_virtual_address = target_section_header.virtual_address + relocation.target.offset;
|
||||
const displacement: i32 = @intCast(@as(i64, @intCast(target_virtual_address)) - @as(i64, @intCast(source_virtual_address)));
|
||||
const address_file_offset: usize = @intCast(@as(i64, @intCast(source_file_offset)) + relocation.offset);
|
||||
const address_file_pointer: *align(1) i32 = @ptrCast(&file.items[address_file_offset]);
|
||||
address_file_pointer.* = displacement;
|
||||
}
|
||||
|
||||
const _start_offset = blk: {
|
||||
const entry_offset = image.section_manager.sections.items[text_section_index].symbol_table.values()[image.entry_point];
|
||||
const text_section_virtual_address = section_headers.items[text_section_index].virtual_address;
|
||||
break :blk text_section_virtual_address + entry_offset;
|
||||
};
|
||||
|
||||
const header: *Header = @ptrCast(file.items.ptr);
|
||||
header.section_header_offset = section_header_offset;
|
||||
header.entry = _start_offset;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
const Header = extern struct {
|
||||
magic: u8 = 0x7f,
|
||||
elf_id: [3]u8 = "ELF".*,
|
||||
bit_count: BitCount = .@"64",
|
||||
endianness: Endianness = .little,
|
||||
header_version: u8 = 1,
|
||||
os_abi: ABI,
|
||||
abi_version: u8 = 0,
|
||||
padding: [7]u8 = [_]u8{0} ** 7,
|
||||
object_type: ObjectFileType = .executable, // e_type
|
||||
machine: Machine,
|
||||
version: u32 = 1,
|
||||
entry: u64,
|
||||
program_header_offset: u64 = std.mem.alignForward(u16, @sizeOf(Header), @alignOf(ProgramHeader)),
|
||||
section_header_offset: u64,
|
||||
flags: u32 = 0,
|
||||
header_size: u16 = 0x40,
|
||||
program_header_size: u16 = @sizeOf(ProgramHeader),
|
||||
program_header_count: u16 = 1,
|
||||
section_header_size: u16 = @sizeOf(SectionHeader),
|
||||
section_header_count: u16,
|
||||
section_header_string_table_index: u16,
|
||||
|
||||
const BitCount = enum(u8) {
|
||||
@"32" = 1,
|
||||
@"64" = 2,
|
||||
};
|
||||
|
||||
const ABI = enum(u8) {
|
||||
systemv = 0,
|
||||
};
|
||||
|
||||
const ObjectFileType = enum(u16) {
|
||||
none = 0,
|
||||
relocatable = 1,
|
||||
executable = 2,
|
||||
dynamic = 3,
|
||||
core = 4,
|
||||
lo_os = 0xfe00,
|
||||
hi_os = 0xfeff,
|
||||
lo_proc = 0xff00,
|
||||
hi_proc = 0xffff,
|
||||
};
|
||||
|
||||
const Machine = enum(u16) {
|
||||
AMD64 = 0x3e,
|
||||
};
|
||||
|
||||
const Endianness = enum(u8) {
|
||||
little = 1,
|
||||
big = 2,
|
||||
};
|
||||
};
|
||||
|
||||
const ProgramHeader = extern struct {
|
||||
type: Type,
|
||||
flags: Flags,
|
||||
offset: u64,
|
||||
virtual_address: u64,
|
||||
physical_address: u64,
|
||||
size_in_file: u64,
|
||||
size_in_memory: u64,
|
||||
alignment: u64,
|
||||
|
||||
const Type = enum(u32) {
|
||||
null = 0,
|
||||
load = 1,
|
||||
dynamic = 2,
|
||||
interpreter = 3,
|
||||
note = 4,
|
||||
shlib = 5, // reserved
|
||||
program_header = 6,
|
||||
tls = 7,
|
||||
lo_os = 0x60000000,
|
||||
hi_os = 0x6fffffff,
|
||||
lo_proc = 0x70000000,
|
||||
hi_proc = 0x7fffffff,
|
||||
};
|
||||
|
||||
const Flags = packed struct(u32) {
|
||||
executable: bool,
|
||||
writable: bool,
|
||||
readable: bool,
|
||||
reserved: u29 = 0,
|
||||
};
|
||||
};
|
||||
const SectionHeader = extern struct {
|
||||
name_offset: u32,
|
||||
type: Type,
|
||||
flags: Flags,
|
||||
virtual_address: u64,
|
||||
file_offset: u64,
|
||||
size: u64,
|
||||
// section index
|
||||
link: u32,
|
||||
info: u32,
|
||||
alignment: u64,
|
||||
entry_size: u64,
|
||||
|
||||
// type
|
||||
const Type = enum(u32) {
|
||||
null = 0,
|
||||
program_data = 1,
|
||||
symbol_table = 2,
|
||||
string_table = 3,
|
||||
relocation_entries_addends = 4,
|
||||
symbol_hash_table = 5,
|
||||
dynamic_linking_info = 6,
|
||||
notes = 7,
|
||||
program_space_no_data = 8,
|
||||
relocation_entries = 9,
|
||||
reserved = 10,
|
||||
dynamic_linker_symbol_table = 11,
|
||||
array_of_constructors = 14,
|
||||
array_of_destructors = 15,
|
||||
array_of_pre_constructors = 16,
|
||||
section_group = 17,
|
||||
extended_section_indices = 18,
|
||||
number_of_defined_types = 19,
|
||||
start_os_specific = 0x60000000,
|
||||
};
|
||||
|
||||
const Flags = packed struct(u64) {
|
||||
writable: bool,
|
||||
alloc: bool,
|
||||
executable: bool,
|
||||
reserved: bool = false,
|
||||
mergeable: bool = false,
|
||||
contains_null_terminated_strings: bool = false,
|
||||
info_link: bool = false,
|
||||
link_order: bool = false,
|
||||
os_non_conforming: bool = false,
|
||||
section_group: bool = false,
|
||||
tls: bool = false,
|
||||
_reserved: u53 = 0,
|
||||
};
|
||||
};
|
||||
|
||||
const SymbolTable = extern struct {
|
||||
const Entry = extern struct {
|
||||
name_offset: u32,
|
||||
information: u8,
|
||||
other: u8,
|
||||
section_header_index: u16,
|
||||
value: u64,
|
||||
size: u64,
|
||||
};
|
||||
};
|
@ -1,270 +0,0 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const log = std.log;
|
||||
const page_size = std.mem.page_size;
|
||||
const assert = std.debug.assert;
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
|
||||
const ir = @import("intermediate_representation.zig");
|
||||
const IR = ir.IR;
|
||||
|
||||
const data_structures = @import("../data_structures.zig");
|
||||
const ArrayList = data_structures.ArrayList;
|
||||
const ArrayListAligned = data_structures.ArrayListAligned;
|
||||
const AutoHashMap = data_structures.AutoHashMap;
|
||||
const mmap = data_structures.mmap;
|
||||
|
||||
const elf = @import("elf.zig");
|
||||
const pe = @import("pe.zig");
|
||||
const macho = @import("macho.zig");
|
||||
|
||||
const jit_callconv = .SysV;
|
||||
|
||||
const Section = struct {
|
||||
bytes: ArrayListAligned(u8, page_size),
|
||||
symbol_table: std.StringArrayHashMapUnmanaged(u32) = .{},
|
||||
name: []const u8,
|
||||
alignment: u32,
|
||||
flags: Section.Flags,
|
||||
type: Section.Type,
|
||||
|
||||
const Type = enum {
|
||||
null,
|
||||
loadable_program,
|
||||
string_table,
|
||||
symbol_table,
|
||||
};
|
||||
|
||||
const Flags = packed struct {
|
||||
read: bool,
|
||||
write: bool,
|
||||
execute: bool,
|
||||
};
|
||||
};
|
||||
|
||||
const SectionCreation = struct {
|
||||
name: []const u8,
|
||||
size_guess: usize,
|
||||
alignment: u32,
|
||||
flags: Section.Flags,
|
||||
type: Section.Type,
|
||||
};
|
||||
|
||||
const Relocation = struct {
|
||||
source: struct {
|
||||
offset: u32,
|
||||
index: u16,
|
||||
},
|
||||
target: struct {
|
||||
offset: u32,
|
||||
index: u16,
|
||||
},
|
||||
offset: i8,
|
||||
};
|
||||
|
||||
pub const SectionManager = struct {
|
||||
sections: ArrayList(Section) = .{},
|
||||
rodata: ?u16 = null,
|
||||
null: bool = false,
|
||||
linker_relocations: ArrayList(Relocation) = .{},
|
||||
allocator: Allocator,
|
||||
|
||||
pub fn addSection(section_manager: *SectionManager, arguments: SectionCreation) !usize {
|
||||
const index = section_manager.sections.items.len;
|
||||
|
||||
const r = try section_manager.insertSection(index, arguments);
|
||||
assert(index == r);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn getTextSectionIndex(section_manager: *const SectionManager) u16 {
|
||||
return @intCast(@intFromBool(section_manager.null));
|
||||
}
|
||||
|
||||
pub fn getTextSection(section_manager: *SectionManager) *Section {
|
||||
return §ion_manager.sections.items[section_manager.getTextSectionIndex()];
|
||||
}
|
||||
|
||||
pub fn insertSection(section_manager: *SectionManager, index: usize, arguments: SectionCreation) !usize {
|
||||
try section_manager.sections.insert(section_manager.allocator, index, .{
|
||||
.bytes = try ArrayListAligned(u8, page_size).initCapacity(section_manager.allocator, arguments.size_guess),
|
||||
.alignment = arguments.alignment,
|
||||
.name = arguments.name,
|
||||
.flags = arguments.flags,
|
||||
.type = arguments.type,
|
||||
});
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn addNullSection(section_manager: *SectionManager) !void {
|
||||
const index = try section_manager.insertSection(0, .{
|
||||
.name = "",
|
||||
.size_guess = page_size,
|
||||
.alignment = page_size,
|
||||
.flags = .{
|
||||
.read = true,
|
||||
.write = false,
|
||||
.execute = false,
|
||||
},
|
||||
.type = .loadable_program,
|
||||
});
|
||||
assert(index == 0);
|
||||
|
||||
section_manager.null = true;
|
||||
}
|
||||
|
||||
pub fn appendByteToSection(section_manager: *SectionManager, section_index: usize, byte: u8) !void {
|
||||
try section_manager.sections.items[section_index].bytes.append(section_manager.allocator, byte);
|
||||
}
|
||||
|
||||
pub fn appendToSection(section_manager: *SectionManager, section_index: usize, bytes: []const u8) !void {
|
||||
try section_manager.sections.items[section_index].bytes.appendSlice(section_manager.allocator, bytes);
|
||||
}
|
||||
|
||||
pub fn getSectionOffset(section_manager: *SectionManager, section_index: usize) usize {
|
||||
return section_manager.sections.items[section_index].bytes.items.len;
|
||||
}
|
||||
|
||||
pub fn getCodeOffset(section_manager: *SectionManager) usize {
|
||||
return section_manager.getSectionOffset(text_section_index);
|
||||
}
|
||||
|
||||
pub fn appendCode(section_manager: *SectionManager, code: []const u8) !void {
|
||||
try section_manager.appendToSection(text_section_index, code);
|
||||
}
|
||||
|
||||
pub fn appendCodeByte(section_manager: *SectionManager, code_byte: u8) !void {
|
||||
try section_manager.appendByteToSection(text_section_index, code_byte);
|
||||
}
|
||||
|
||||
const text_section_index = 0;
|
||||
};
|
||||
|
||||
pub const Result = struct {
|
||||
section_manager: SectionManager,
|
||||
entry_point: u32,
|
||||
target: std.Target,
|
||||
|
||||
pub fn create(section_manager: SectionManager, target: std.Target, entry_point_index: u32) !Result {
|
||||
const result = Result{
|
||||
.section_manager = section_manager,
|
||||
.target = target,
|
||||
.entry_point = entry_point_index,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn getEntryPoint(image: *const Result, comptime FunctionType: type) *const FunctionType {
|
||||
if (@import("builtin").cpu.arch == .aarch64 and @import("builtin").os.tag == .macos) {
|
||||
data_structures.pthread_jit_write_protect_np(true);
|
||||
}
|
||||
comptime {
|
||||
assert(@typeInfo(FunctionType) == .Fn);
|
||||
}
|
||||
|
||||
assert(image.sections.text.content.len > 0);
|
||||
return @as(*const FunctionType, @ptrCast(&image.sections.text.content[image.entry_point]));
|
||||
}
|
||||
|
||||
fn writeElf(image: *Result, executable_relative_path: []const u8) !void {
|
||||
const file_in_memory = try elf.writeToMemory(image);
|
||||
try writeFile(file_in_memory.items, executable_relative_path);
|
||||
}
|
||||
|
||||
fn writeFile(bytes: []const u8, path: []const u8) !void {
|
||||
const flags = switch (@import("builtin").os.tag) {
|
||||
.windows => .{},
|
||||
else => .{
|
||||
.mode = 0o777,
|
||||
},
|
||||
};
|
||||
|
||||
const file_descriptor = try std.fs.cwd().createFile(path, flags);
|
||||
try file_descriptor.writeAll(bytes);
|
||||
file_descriptor.close();
|
||||
}
|
||||
|
||||
fn writePe(image: *Result, executable_relative_path: []const u8) !void {
|
||||
_ = executable_relative_path;
|
||||
_ = image;
|
||||
// var writer = try pe.Writer.init(allocator);
|
||||
// try writer.writeToMemory(image);
|
||||
// try writer.writeToFile(executable_relative_path);
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn InstructionSelector(comptime Instruction: type) type {
|
||||
return struct {
|
||||
functions: ArrayList(Function),
|
||||
allocator: Allocator,
|
||||
|
||||
pub const Function = struct {
|
||||
instructions: ArrayList(Instruction) = .{},
|
||||
relocations: ArrayList(u32) = .{},
|
||||
block_map: AutoHashMap(ir.BasicBlock.Index, u32) = .{},
|
||||
|
||||
pub fn addInstruction(function: *Function, allocator: Allocator, instruction: Instruction) !u32 {
|
||||
const index = function.instructions.items.len;
|
||||
try function.instructions.append(allocator, instruction);
|
||||
|
||||
return @intCast(index);
|
||||
}
|
||||
};
|
||||
|
||||
const Selector = @This();
|
||||
};
|
||||
}
|
||||
|
||||
const x86_64 = @import("x86_64.zig");
|
||||
const aarch64 = @import("aarch64.zig");
|
||||
|
||||
pub const Logger = x86_64.Logger;
|
||||
|
||||
pub fn get(comptime arch: std.Target.Cpu.Arch) type {
|
||||
const backend = switch (arch) {
|
||||
.x86_64 => x86_64,
|
||||
.aarch64 => aarch64,
|
||||
else => {},
|
||||
};
|
||||
|
||||
return struct {
|
||||
pub fn initialize(allocator: Allocator, intermediate: *IR, descriptor: Compilation.Module.Descriptor) !void {
|
||||
switch (arch) {
|
||||
.x86_64 => {
|
||||
var mir = try backend.MIR.selectInstructions(allocator, intermediate, descriptor.target);
|
||||
try mir.allocateRegisters();
|
||||
const os = descriptor.target.os.tag;
|
||||
const image = try mir.encode();
|
||||
|
||||
switch (os) {
|
||||
.linux => try image.writeElf(descriptor.executable_path),
|
||||
.windows => try image.writePe(descriptor.executable_path),
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
else => {
|
||||
const file = try std.fs.cwd().readFileAlloc(allocator, "main", std.math.maxInt(u64));
|
||||
try macho.interpretFile(allocator, descriptor, file);
|
||||
},
|
||||
}
|
||||
|
||||
// switch (@import("builtin").os.tag) {
|
||||
// .linux => switch (@import("builtin").cpu.arch == arch) {
|
||||
// true => {
|
||||
// const entryPoint = result.getEntryPoint(fn () callconv(.SysV) noreturn);
|
||||
// entryPoint();
|
||||
// },
|
||||
// false => {},
|
||||
// },
|
||||
// else => {},
|
||||
// }
|
||||
}
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,696 +0,0 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const equal = std.mem.eql;
|
||||
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
|
||||
const data_structures = @import("../data_structures.zig");
|
||||
const ArrayList = data_structures.ArrayList;
|
||||
const mmap = data_structures.mmap;
|
||||
|
||||
const Header = extern struct {
|
||||
magic: u32 = magic,
|
||||
cpu_type: CpuType,
|
||||
cpu_subtype: extern union {
|
||||
arm: ArmSubType,
|
||||
x86: X86SubType,
|
||||
},
|
||||
file_type: FileType,
|
||||
load_command_count: u32,
|
||||
load_command_size: u32,
|
||||
flags: Flags,
|
||||
reserved: u32 = 0,
|
||||
|
||||
const magic = 0xfeedfacf;
|
||||
|
||||
const CpuType = enum(u32) {
|
||||
VAX = 0x00000001,
|
||||
ROMP = 0x00000002,
|
||||
NS32032 = 0x00000004,
|
||||
NS32332 = 0x00000005,
|
||||
MC680x0 = 0x00000006,
|
||||
x86 = 0x00000007,
|
||||
MIPS = 0x00000008,
|
||||
NS32352 = 0x00000009,
|
||||
MC98000 = 0x0000000A,
|
||||
HPPA = 0x0000000B,
|
||||
ARM = 0x0000000C,
|
||||
MC88000 = 0x0000000D,
|
||||
SPARC = 0x0000000E,
|
||||
i860be = 0x0000000F,
|
||||
i860_le = 0x00000010,
|
||||
RS6000 = 0x00000011,
|
||||
PowerPC = 0x00000012,
|
||||
arm64 = 0x0000000C | abi64,
|
||||
x86_64 = 0x00000007 | abi64,
|
||||
|
||||
const abi64 = 0x01000000;
|
||||
};
|
||||
|
||||
const ArmSubType = enum(u32) {
|
||||
all = 0x00000000,
|
||||
ARM_A500_ARCH = 0x00000001,
|
||||
ARM_A500 = 0x00000002,
|
||||
ARM_A440 = 0x00000003,
|
||||
ARM_M4 = 0x00000004,
|
||||
ARM_V4T = 0x00000005,
|
||||
ARM_V6 = 0x00000006,
|
||||
ARM_V5TEJ = 0x00000007,
|
||||
ARM_XSCALE = 0x00000008,
|
||||
ARM_V7 = 0x00000009,
|
||||
ARM_V7F = 0x0000000A,
|
||||
ARM_V7S = 0x0000000B,
|
||||
ARM_V7K = 0x0000000C,
|
||||
ARM_V8 = 0x0000000D,
|
||||
ARM_V6M = 0x0000000E,
|
||||
ARM_V7M = 0x0000000F,
|
||||
ARM_V7EM = 0x00000010,
|
||||
_,
|
||||
};
|
||||
|
||||
const X86SubType = enum(u32) {
|
||||
All = 0x00000003,
|
||||
@"486" = 0x00000004,
|
||||
@"486SX" = 0x00000084,
|
||||
Pentium_M5 = 0x00000056,
|
||||
Celeron = 0x00000067,
|
||||
Celeron_Mobile = 0x00000077,
|
||||
Pentium_3 = 0x00000008,
|
||||
Pentium_3_M = 0x00000018,
|
||||
Pentium_3_XEON = 0x00000028,
|
||||
Pentium_4 = 0x0000000A,
|
||||
Itanium = 0x0000000B,
|
||||
Itanium_2 = 0x0000001B,
|
||||
XEON = 0x0000000C,
|
||||
XEON_MP = 0x0000001C,
|
||||
_,
|
||||
};
|
||||
|
||||
const FileType = enum(u32) {
|
||||
relocatable_object = 0x00000001,
|
||||
demand_paged_executable = 0x00000002,
|
||||
fixed_vm_shared_library = 0x00000003,
|
||||
core = 0x00000004,
|
||||
preloaded_executable = 0x00000005,
|
||||
dynamic_shared_library = 0x00000006,
|
||||
dynamic_link_editor = 0x00000007,
|
||||
dynamic_bundle = 0x00000008,
|
||||
shared_library_stub = 0x00000009,
|
||||
debug_companion = 0x0000000A,
|
||||
x86_64_kext = 0x0000000B,
|
||||
archive = 0x0000000C,
|
||||
};
|
||||
|
||||
const Flags = packed struct(u32) {
|
||||
no_undefined_references: bool = true,
|
||||
incrementally_linked: bool = false,
|
||||
dynamic_linker_input: bool = true,
|
||||
dynamic_linker_bound_undefined_references: bool = false,
|
||||
prebound_dynamic_undefined_references: bool = false,
|
||||
split_ro_and_rw_segments: bool = false,
|
||||
_: bool = false,
|
||||
two_level_namespace_bindings: bool = true,
|
||||
no_symbol_multiple_definition_in_subimages: bool = false,
|
||||
no_dyld_prebinding_agent_notification: bool = false,
|
||||
can_redo_prebinding: bool = false,
|
||||
bind_two_level_namespaces_to_libraries: bool = false,
|
||||
safe_to_split_sections_for_dead_code_stripping: bool = false,
|
||||
canonicalized_by_unprebinding: bool = false,
|
||||
final_external_weak_symbols: bool = false,
|
||||
final_weak_symbols: bool = false,
|
||||
all_stacks_execute_protected: bool = false,
|
||||
safe_for_zero_uid: bool = false,
|
||||
safe_for_ugid: bool = false,
|
||||
no_check_dependent_dylibs_for_reexport: bool = false,
|
||||
load_at_random_address: bool = false,
|
||||
no_load_command_for_unreferenced_dylib: bool = true,
|
||||
thread_local_variable_section: bool = false,
|
||||
run_with_non_executable_heap: bool = false,
|
||||
code_linked_for_application_use: bool = false,
|
||||
nlist_external_symbols_not_all_dyld_info_symbols: bool = false,
|
||||
allow_lc_min_version_macos_lc_build_version: bool = false,
|
||||
reserved: u4 = 0,
|
||||
dylib_only: bool = false,
|
||||
};
|
||||
};
|
||||
|
||||
const UniversalHeader = extern struct {
|
||||
magic: u32 = magic,
|
||||
binary_count: u32,
|
||||
|
||||
const magic = 0xcafebabe;
|
||||
};
|
||||
|
||||
const LoadCommand = extern struct {
|
||||
type: Type,
|
||||
size: u32,
|
||||
|
||||
const Type = enum(u32) {
|
||||
segment32 = 0x01,
|
||||
symbol_table = 0x02,
|
||||
symbol_table_information = 0x0b,
|
||||
load_dylib = 0x0c,
|
||||
id_dylib = 0x0d,
|
||||
load_dylinker = 0x0e,
|
||||
id_dylinker = 0x0f,
|
||||
optional_dynamic_library = 0x18,
|
||||
segment64 = 0x19,
|
||||
uuid_number = 0x1b,
|
||||
code_signature = 0x1d,
|
||||
compressed_linkedit_table = 0x22,
|
||||
function_starts = 0x26,
|
||||
data_in_code = 0x29,
|
||||
source_version = 0x2a,
|
||||
minimum_os_version = 0x32,
|
||||
dyld_exports_trie = 0x80000033,
|
||||
dyld_chained_fixups = 0x80000034,
|
||||
dyld_main_entry_point = 0x80000028,
|
||||
};
|
||||
|
||||
const Segment64 = extern struct {
|
||||
type: Type = .segment64,
|
||||
size: u32,
|
||||
name: [16]u8,
|
||||
address: u64,
|
||||
address_size: u64,
|
||||
file_offset: u64,
|
||||
file_size: u64,
|
||||
maximum_virtual_memory_protections: VirtualMemoryProtection,
|
||||
initial_virtual_memory_protections: VirtualMemoryProtection,
|
||||
section_count: u32,
|
||||
flags: Flags,
|
||||
|
||||
const VirtualMemoryProtection = packed struct(u32) {
|
||||
read: bool,
|
||||
write: bool,
|
||||
execute: bool,
|
||||
reserved: u29 = 0,
|
||||
};
|
||||
|
||||
const Flags = packed struct(u32) {
|
||||
vm_space_high_part: bool = false,
|
||||
vm_fixed_library: bool = false,
|
||||
no_relocation: bool = false,
|
||||
protected_segment: bool = false,
|
||||
read_only_after_relocations: bool = false,
|
||||
reserved: u27 = 0,
|
||||
};
|
||||
|
||||
const Section = extern struct {
|
||||
name: [16]u8,
|
||||
segment_name: [16]u8,
|
||||
address: u64,
|
||||
size: u64,
|
||||
file_offset: u32,
|
||||
alignment: u32,
|
||||
relocation_file_offset: u32,
|
||||
relocation_count: u32,
|
||||
type: Section.Type,
|
||||
reserved: u8 = 0,
|
||||
flags: Section.Flags,
|
||||
reserved0: u32 = 0,
|
||||
reserved1: u32 = 0,
|
||||
reserved2: u32 = 0,
|
||||
|
||||
comptime {
|
||||
assert(@sizeOf(Section) == 80);
|
||||
}
|
||||
|
||||
const Type = enum(u8) {
|
||||
regular = 0,
|
||||
only_non_lazy_symbol_pointers = 0b110,
|
||||
only_lazy_symbol_pointers_only_symbol_stubs = 0b111,
|
||||
zero_fill_on_demand_section = 0b1100,
|
||||
only_lazy_pointers_to_lazy_loaded_dylibs = 0b10000,
|
||||
};
|
||||
|
||||
const Flags = packed struct(u16) {
|
||||
local_relocations: bool = false,
|
||||
external_relocations: bool = false,
|
||||
some_machine_instructions: bool = false,
|
||||
reserved: u5 = 0,
|
||||
reserved2: u1 = 0,
|
||||
debug_section: bool = false,
|
||||
i386_code_stubs: bool = false,
|
||||
live_blocks_if_reference_live_blocks: bool = false,
|
||||
no_dead_stripping: bool = false,
|
||||
strip_static_symbols_dyldlink_flag: bool = false,
|
||||
coalesced_symbols: bool = false,
|
||||
only_machine_instructions: bool = false,
|
||||
};
|
||||
};
|
||||
|
||||
fn getSize(section_count: u32) u32 {
|
||||
return @sizeOf(LoadCommand.Segment64) + section_count * @sizeOf(LoadCommand.Segment64.Section);
|
||||
}
|
||||
};
|
||||
|
||||
const LinkeditData = extern struct {
|
||||
type: Type,
|
||||
size: u32 = 16,
|
||||
data_offset: u32,
|
||||
data_size: u32,
|
||||
};
|
||||
|
||||
const SymbolTable = extern struct {
|
||||
type: Type,
|
||||
size: u32 = 24,
|
||||
symbol_offset: u32,
|
||||
symbol_count: u32,
|
||||
string_table_offset: u32,
|
||||
string_table_size: u32,
|
||||
};
|
||||
|
||||
const SymbolTableInformation = extern struct {
|
||||
type: Type,
|
||||
size: u32 = 80,
|
||||
local_symbol_index: u32,
|
||||
local_symbol_count: u32,
|
||||
external_symbol_index: u32,
|
||||
external_symbol_count: u32,
|
||||
undefined_symbol_index: u32,
|
||||
undefined_symbol_count: u32,
|
||||
content_table_offset: u32,
|
||||
content_table_entry_count: u32,
|
||||
module_table_offset: u32,
|
||||
module_table_entry_count: u32,
|
||||
referenced_symbol_table_offset: u32,
|
||||
referenced_symbol_table_entry_count: u32,
|
||||
indirect_symbol_table_offset: u32,
|
||||
indirect_symbol_table_entry_count: u32,
|
||||
external_relocation_offset: u32,
|
||||
external_relocation_entry_count: u32,
|
||||
local_relocation_offset: u32,
|
||||
local_relocation_entry_count: u32,
|
||||
};
|
||||
|
||||
const Dylinker = extern struct {
|
||||
type: Type,
|
||||
size: u32,
|
||||
name_offset: u32 = 12,
|
||||
};
|
||||
|
||||
const Dylib = extern struct {
|
||||
type: Type,
|
||||
size: u32,
|
||||
name_offset: u32,
|
||||
timestamp: u32,
|
||||
current_version: u32,
|
||||
compatibility_version: u32,
|
||||
};
|
||||
|
||||
const Uuid = extern struct {
|
||||
type: Type,
|
||||
size: u32,
|
||||
uuid: [16]u8,
|
||||
};
|
||||
|
||||
const MinimumVersion = extern struct {
|
||||
type: Type,
|
||||
size: u32,
|
||||
version: u32,
|
||||
sdk: u32,
|
||||
};
|
||||
|
||||
const SourceVersion = extern struct {
|
||||
type: Type,
|
||||
size: u32,
|
||||
version: u64,
|
||||
};
|
||||
|
||||
const EntryPoint = extern struct {
|
||||
type: Type,
|
||||
size: u32,
|
||||
entry_offset: u64,
|
||||
stack_size: u64,
|
||||
};
|
||||
};
|
||||
|
||||
const Writer = struct {
|
||||
items: []u8,
|
||||
index: usize = 0,
|
||||
address_offset: usize = 0,
|
||||
file_offset: usize = 0,
|
||||
load_command_size: u32,
|
||||
segment_count: u16,
|
||||
segment_index: u16 = 0,
|
||||
segment_offset: u16 = @sizeOf(Header),
|
||||
linkedit_segment_address_offset: u64 = 0,
|
||||
linkedit_segment_file_offset: u64 = 0,
|
||||
linkedit_segment_size: u32 = 0,
|
||||
|
||||
fn getWrittenBytes(writer: *const Writer) []const u8 {
|
||||
return writer.items[0..writer.index];
|
||||
}
|
||||
|
||||
fn append(writer: *Writer, bytes: []const u8) void {
|
||||
writer.writeBytesAt(bytes, writer.index);
|
||||
writer.index += bytes.len;
|
||||
}
|
||||
|
||||
fn writeBytesAt(writer: *Writer, bytes: []const u8, offset: usize) void {
|
||||
@memcpy(writer.items[offset..][0..bytes.len], bytes);
|
||||
}
|
||||
|
||||
const SegmentCreation = struct {
|
||||
name: []const u8,
|
||||
sections: []const SectionCreation,
|
||||
protection: LoadCommand.Segment64.VirtualMemoryProtection,
|
||||
};
|
||||
|
||||
const SectionCreation = struct {
|
||||
name: []const u8,
|
||||
bytes: []const u8,
|
||||
alignment: u32 = 1,
|
||||
flags: LoadCommand.Segment64.Section.Flags,
|
||||
};
|
||||
|
||||
fn writeSegment(writer: *Writer, descriptor: SegmentCreation) void {
|
||||
assert(writer.segment_index < writer.segment_count);
|
||||
defer writer.segment_index += 1;
|
||||
|
||||
const segment_name = blk: {
|
||||
var result = [1]u8{0} ** 16;
|
||||
@memcpy(result[0..descriptor.name.len], descriptor.name);
|
||||
break :blk result;
|
||||
};
|
||||
|
||||
if (equal(u8, descriptor.name, "__PAGEZERO")) {
|
||||
assert(writer.segment_offset == @sizeOf(Header));
|
||||
const address_size = 4 * 1024 * 1024 * 1024;
|
||||
writer.writeBytesAt(std.mem.asBytes(&LoadCommand.Segment64{
|
||||
.size = @sizeOf(LoadCommand.Segment64),
|
||||
.name = segment_name,
|
||||
.address = 0,
|
||||
.address_size = address_size,
|
||||
.file_offset = 0,
|
||||
.file_size = 0,
|
||||
.maximum_virtual_memory_protections = descriptor.protection,
|
||||
.initial_virtual_memory_protections = descriptor.protection,
|
||||
.section_count = @intCast(descriptor.sections.len),
|
||||
.flags = .{},
|
||||
}), writer.segment_offset);
|
||||
|
||||
writer.address_offset += address_size;
|
||||
writer.segment_offset += @sizeOf(LoadCommand.Segment64);
|
||||
} else if (equal(u8, descriptor.name, "__TEXT")) {
|
||||
const original_offset = writer.segment_offset;
|
||||
assert(original_offset == @sizeOf(Header) + @sizeOf(LoadCommand.Segment64));
|
||||
writer.segment_offset += @sizeOf(LoadCommand.Segment64);
|
||||
|
||||
const text_metadata_offset = @sizeOf(Header) + writer.load_command_size;
|
||||
var section_address_offset = writer.address_offset + text_metadata_offset;
|
||||
var section_file_offset = writer.file_offset + text_metadata_offset;
|
||||
|
||||
for (descriptor.sections) |section| {
|
||||
section_address_offset = std.mem.alignForward(usize, section_address_offset, section.alignment);
|
||||
section_file_offset = std.mem.alignForward(usize, section_file_offset, section.alignment);
|
||||
|
||||
writer.writeBytesAt(std.mem.asBytes(&LoadCommand.Segment64.Section{
|
||||
.name = blk: {
|
||||
var result = [1]u8{0} ** 16;
|
||||
@memcpy(result[0..section.name.len], section.name);
|
||||
break :blk result;
|
||||
},
|
||||
.segment_name = segment_name,
|
||||
.address = section_address_offset,
|
||||
.size = section.bytes.len,
|
||||
.file_offset = @intCast(section_file_offset),
|
||||
.alignment = std.math.log2(section.alignment),
|
||||
.relocation_file_offset = 0,
|
||||
.relocation_count = 0,
|
||||
.type = .regular,
|
||||
.flags = section.flags,
|
||||
}), writer.segment_offset);
|
||||
|
||||
@memcpy(writer.items[section_file_offset..][0..section.bytes.len], section.bytes);
|
||||
|
||||
section_address_offset += section.bytes.len;
|
||||
section_file_offset += section.bytes.len;
|
||||
|
||||
writer.segment_offset += @sizeOf(LoadCommand.Segment64.Section);
|
||||
}
|
||||
|
||||
const end_segment_offset = writer.segment_offset;
|
||||
writer.segment_offset = original_offset;
|
||||
|
||||
const size = end_segment_offset - writer.file_offset;
|
||||
const aligned_size = std.mem.alignForward(usize, size, 16 * 1024);
|
||||
|
||||
writer.append(std.mem.asBytes(&LoadCommand.Segment64{
|
||||
.size = @sizeOf(LoadCommand.Segment64),
|
||||
.name = segment_name,
|
||||
.address = writer.address_offset,
|
||||
.address_size = aligned_size,
|
||||
.file_offset = writer.file_offset,
|
||||
.file_size = aligned_size,
|
||||
.maximum_virtual_memory_protections = descriptor.protection,
|
||||
.initial_virtual_memory_protections = descriptor.protection,
|
||||
.section_count = @intCast(descriptor.sections.len),
|
||||
.flags = .{},
|
||||
}));
|
||||
|
||||
writer.segment_offset = end_segment_offset;
|
||||
|
||||
writer.address_offset += aligned_size;
|
||||
writer.file_offset += aligned_size;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
fn writeLinkeditData(writer: *Writer, bytes: []const u8, load_command_type: LoadCommand.Type) void {
|
||||
if (writer.linkedit_segment_size == 0) {
|
||||
writer.linkedit_segment_address_offset = writer.address_offset;
|
||||
writer.linkedit_segment_file_offset = writer.file_offset;
|
||||
}
|
||||
|
||||
const data_size: u32 = @intCast(bytes.len);
|
||||
@memcpy(writer.items[writer.file_offset..][0..data_size], bytes);
|
||||
|
||||
writer.append(std.mem.asBytes(&LoadCommand.LinkeditData{
|
||||
.type = load_command_type,
|
||||
.data_offset = @intCast(writer.linkedit_segment_file_offset),
|
||||
.data_size = data_size,
|
||||
}));
|
||||
|
||||
writer.address_offset += data_size;
|
||||
writer.file_offset += data_size;
|
||||
|
||||
writer.linkedit_segment_size += data_size;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn interpretFile(allocator: Allocator, descriptor: Compilation.Module.Descriptor, file: []const u8) !void {
|
||||
_ = allocator;
|
||||
_ = descriptor;
|
||||
const header: *const Header = @ptrCast(@alignCast(file.ptr));
|
||||
//print("Header : {}", .{header});
|
||||
assert(header.magic == Header.magic);
|
||||
|
||||
var text_segment: LoadCommand.Segment64 = undefined;
|
||||
const load_command_start: *const LoadCommand = @ptrCast(@alignCast(file[@sizeOf(Header)..].ptr));
|
||||
var load_command_ptr = load_command_start;
|
||||
|
||||
for (0..header.load_command_count) |_| {
|
||||
const load_command = load_command_ptr.*;
|
||||
switch (load_command.type) {
|
||||
.segment64 => {
|
||||
const segment_load_command: *const LoadCommand.Segment64 = @ptrCast(@alignCast(load_command_ptr));
|
||||
const text_segment_name = "__TEXT";
|
||||
if (equal(u8, segment_load_command.name[0..text_segment_name.len], text_segment_name)) {
|
||||
text_segment = segment_load_command.*;
|
||||
}
|
||||
//print("SLC: {}", .{segment_load_command});
|
||||
//print("segment name: {s}", .{segment_load_command.name});
|
||||
const section_ptr: [*]const LoadCommand.Segment64.Section = @ptrFromInt(@intFromPtr(segment_load_command) + @sizeOf(LoadCommand.Segment64));
|
||||
const sections = section_ptr[0..segment_load_command.section_count];
|
||||
for (sections) |section| {
|
||||
_ = section;
|
||||
//print("{}", .{section});
|
||||
//print("Section name: {s}. Segment name: {s}", .{ section.name, section.segment_name });
|
||||
}
|
||||
},
|
||||
.dyld_chained_fixups => {
|
||||
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.dyld_exports_trie => {
|
||||
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.symbol_table => {
|
||||
const command: *const LoadCommand.SymbolTable = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.symbol_table_information => {
|
||||
const command: *const LoadCommand.SymbolTableInformation = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.load_dylinker => {
|
||||
const command: *const LoadCommand.Dylinker = @ptrCast(@alignCast(load_command_ptr));
|
||||
//print("command: {}", .{command});
|
||||
const name: [*:0]const u8 = @ptrFromInt(@intFromPtr(command) + command.name_offset);
|
||||
_ = name;
|
||||
//print("Name: {s}", .{name});
|
||||
},
|
||||
.uuid_number => {
|
||||
const command: *const LoadCommand.Uuid = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.minimum_os_version => {
|
||||
const command: *const LoadCommand.MinimumVersion = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.source_version => {
|
||||
const command: *const LoadCommand.SourceVersion = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.dyld_main_entry_point => {
|
||||
const command: *const LoadCommand.EntryPoint = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.load_dylib => {
|
||||
const command: *const LoadCommand.Dylib = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
//print("Dylib: {s}", .{@as([*:0]const u8, @ptrFromInt(@intFromPtr(load_command_ptr) + @sizeOf(LoadCommand.Dylib)))});
|
||||
},
|
||||
.function_starts => {
|
||||
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.data_in_code => {
|
||||
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
.code_signature => {
|
||||
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
|
||||
_ = command;
|
||||
//print("command: {}", .{command});
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
||||
load_command_ptr = @ptrFromInt(@intFromPtr(load_command_ptr) + load_command.size);
|
||||
}
|
||||
|
||||
// const load_command_end = load_command_ptr;
|
||||
// const load_command_size = @intFromPtr(load_command_end) - @intFromPtr(load_command_start);
|
||||
// assert(load_command_size == header.load_command_size);
|
||||
|
||||
const segment_count = 3;
|
||||
var writer = Writer{
|
||||
.items = try mmap(0x100000, .{}),
|
||||
.load_command_size = segment_count * @sizeOf(LoadCommand.Segment64) +
|
||||
2 * @sizeOf(LoadCommand.Segment64.Section) +
|
||||
@sizeOf(LoadCommand.LinkeditData) +
|
||||
@sizeOf(LoadCommand.LinkeditData) +
|
||||
@sizeOf(LoadCommand.SymbolTable) +
|
||||
@sizeOf(LoadCommand.SymbolTableInformation) +
|
||||
@sizeOf(LoadCommand.Dylinker) + std.mem.alignForward(u32, "/usr/lib/dyld".len, 8) +
|
||||
@sizeOf(LoadCommand.Uuid) +
|
||||
@sizeOf(LoadCommand.MinimumVersion) +
|
||||
@sizeOf(LoadCommand.EntryPoint) +
|
||||
@sizeOf(LoadCommand.Dylib) + std.mem.alignForward(u32, "/usr/lib/libSystem.B.dylib".len, 8) +
|
||||
3 * @sizeOf(LoadCommand.LinkeditData),
|
||||
.segment_count = segment_count,
|
||||
};
|
||||
writer.index = @sizeOf(Header);
|
||||
writer.writeSegment(.{
|
||||
.name = "__PAGEZERO",
|
||||
.sections = &.{},
|
||||
.protection = .{
|
||||
.read = false,
|
||||
.write = false,
|
||||
.execute = false,
|
||||
},
|
||||
});
|
||||
writer.writeSegment(.{
|
||||
.name = "__TEXT",
|
||||
.sections = &.{
|
||||
.{
|
||||
.name = "__text",
|
||||
.bytes = &.{
|
||||
0x00, 0x00, 0x80, 0x52,
|
||||
0xc0, 0x03, 0x5f, 0xd6,
|
||||
},
|
||||
.alignment = 4,
|
||||
.flags = .{
|
||||
.only_machine_instructions = true,
|
||||
},
|
||||
},
|
||||
.{
|
||||
.name = "__unwind_info",
|
||||
.bytes = &.{
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
0xb0, 0x3f, 0x00, 0x00,
|
||||
0x34, 0x00, 0x00, 0x00,
|
||||
0x34, 0x00, 0x00, 0x00,
|
||||
0xb9, 0x3f, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x34, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x01, 0x00,
|
||||
0x10, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02,
|
||||
},
|
||||
.alignment = 4,
|
||||
.flags = .{},
|
||||
},
|
||||
},
|
||||
.protection = .{
|
||||
.read = true,
|
||||
.write = false,
|
||||
.execute = true,
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: write this later
|
||||
|
||||
// writer.writeSegment(.{
|
||||
// .name = "__LINKEDIT",
|
||||
// .sections = &.{},
|
||||
// .protection = .{
|
||||
// .read = true,
|
||||
// .write = false,
|
||||
// .execute = false,
|
||||
// },
|
||||
// });
|
||||
assert(writer.segment_index == writer.segment_count - 1);
|
||||
writer.index = writer.segment_offset + @sizeOf(LoadCommand.Segment64);
|
||||
|
||||
for (file[16384 + 56 ..][0..48]) |b| {
|
||||
_ = b;
|
||||
//print("0x{x}, ", .{b});
|
||||
}
|
||||
|
||||
const chained_fixup_bytes = &.{ 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
|
||||
writer.writeLinkeditData(chained_fixup_bytes, .dyld_chained_fixups);
|
||||
const export_trie_bytes = &.{ 0x0, 0x1, 0x5f, 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x2, 0x5f, 0x6d, 0x68, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x0, 0x5, 0x6d, 0x61, 0x69, 0x6e, 0x0, 0x25, 0x3, 0x0, 0xb0, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
|
||||
writer.writeLinkeditData(export_trie_bytes, .dyld_exports_trie);
|
||||
unreachable;
|
||||
// writer.writeSymbolTable(
|
||||
}
|
||||
|
||||
// .bytes = &.{
|
||||
// 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5f, 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x2, 0x5f, 0x6d, 0x68, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x0, 0x5, 0x6d, 0x61, 0x69, 0x6e, 0x0, 0x25, 0x3, 0x0, 0xb0, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb0, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xf, 0x1, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xf, 0x1, 0x0, 0x0, 0xb0, 0x3f, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x20, 0x0, 0x5f, 0x5f, 0x6d, 0x68, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x0, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfa, 0xde, 0xc, 0xc0, 0x0, 0x0, 0x1, 0x11, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0xfa, 0xde, 0xc, 0x2, 0x0, 0x0, 0x0, 0xfd, 0x0, 0x2, 0x4, 0x0, 0x0, 0x2, 0x0, 0x2, 0x0, 0x0, 0x0, 0x5d, 0x0, 0x0, 0x0, 0x58, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x40, 0xb0, 0x20, 0x2, 0x0, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6d, 0x61, 0x69, 0x6e, 0x0, 0xb2, 0x2a, 0x3, 0x79, 0x1b, 0x82, 0xf4, 0x71, 0xf1, 0xae, 0xfa, 0x44, 0x53, 0xe0, 0xc2, 0x78, 0x1e, 0x56, 0xd1, 0x9b, 0x36, 0x37, 0x7b, 0x7e, 0x61, 0xf5, 0x8a, 0x59, 0xc4, 0xf0, 0x64, 0x56, 0xad, 0x7f, 0xac, 0xb2, 0x58, 0x6f, 0xc6, 0xe9, 0x66, 0xc0, 0x4, 0xd7, 0xd1, 0xd1, 0x6b, 0x2, 0x4f, 0x58, 0x5, 0xff, 0x7c, 0xb4, 0x7c, 0x7a, 0x85, 0xda, 0xbd, 0x8b, 0x48, 0x89, 0x2c, 0xa7, 0xad, 0x7f, 0xac, 0xb2, 0x58, 0x6f, 0xc6, 0xe9, 0x66, 0xc0, 0x4, 0xd7, 0xd1, 0xd1, 0x6b, 0x2, 0x4f, 0x58, 0x5, 0xff, 0x7c, 0xb4, 0x7c, 0x7a, 0x85, 0xda, 0xbd, 0x8b, 0x48, 0x89, 0x2c, 0xa7, 0x8, 0xdb, 0xee, 0xf5, 0x95, 0x71, 0x3e, 0xcb, 0x29, 0xff, 0x3f, 0x28, 0x46, 0xf0, 0xdc, 0x97, 0xbf, 0x2d, 0x3, 0xf2, 0xec, 0xc, 0x84, 0xa, 0x44, 0x90, 0xf, 0xe0, 0xf4, 0xea, 0x67, 0x97, 0x6b, 0xb0, 0x22, 0x2, 0x0, 0xa7, 0xed, 0x94, 0xb2, 0x3d, 0x86, 0x4d, 0x13, 0xd6, 0xa4, 0xe, 0x1c, 0x1a, 0x6b, 0x9b, 0x82, 0xa0, 0xeb, 0x28, 0x23, 0xfe, 0x8a, 0x51, 0x2a, 0xe5, 0xf9, 0x39,
|
||||
// },
|
@ -1,267 +0,0 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const data_structures = @import("../data_structures.zig");
|
||||
const ArrayList = data_structures.ArrayList;
|
||||
const emit = @import("emit.zig");
|
||||
pub const Writer = struct {
|
||||
in_file: []const u8,
|
||||
items: []u8,
|
||||
index: usize = 0,
|
||||
allocator: Allocator,
|
||||
pub fn init(allocator: Allocator) !Writer {
|
||||
const file = try std.fs.cwd().readFileAlloc(allocator, "main.exe", 0xfffffffffffff);
|
||||
const len = std.mem.alignForward(usize, file.len, 0x1000);
|
||||
return Writer{
|
||||
.in_file = file,
|
||||
.items = try data_structures.mmap(len, .{}),
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn writeToMemory(writer: *Writer, image: *const emit.Result) !void {
|
||||
//print("File len: {}", .{writer.in_file.len});
|
||||
const dos_header: *const ImageDosHeader = @ptrCast(@alignCast(writer.in_file.ptr));
|
||||
//print("File address: {}", .{dos_header.file_address_of_new_exe_header});
|
||||
//print("File: {s}", .{writer.in_file[0x40..]});
|
||||
for (writer.in_file[0x40..], 0..) |byte, index| {
|
||||
_ = index;
|
||||
if (byte == 'T') {
|
||||
//print("Index: {}", .{index});
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(dos_header.magic_number == ImageDosHeader.magic);
|
||||
// assert(dos_header.file_address_of_new_exe_header == @sizeOf(ImageDosHeader));
|
||||
//print("{}", .{dos_header});
|
||||
const file_header: *const ImageFileHeader = @ptrCast(@alignCast(writer.in_file[dos_header.file_address_of_new_exe_header + 4 ..].ptr));
|
||||
_ = file_header;
|
||||
//print("File header: {}", .{file_header});
|
||||
|
||||
writer.append(std.mem.asBytes(&ImageDosHeader{
|
||||
.file_address_of_new_exe_header = 208,
|
||||
}));
|
||||
while (writer.index < 208) : (writer.index += 1) {
|
||||
writer.append(&.{0});
|
||||
}
|
||||
writer.append(std.mem.asBytes(&image_NT_signature));
|
||||
writer.append(std.mem.asBytes(&ImageFileHeader{
|
||||
.machine = switch (image.target.cpu.arch) {
|
||||
.x86_64 => .amd64,
|
||||
.aarch64 => .arm64,
|
||||
else => @panic("Architecture"),
|
||||
},
|
||||
.section_count = 3,
|
||||
.time_date_stamp = @intCast(std.time.timestamp()),
|
||||
}));
|
||||
|
||||
const kernel32 = blk: {
|
||||
var library = Library{
|
||||
.name = "KERNEL32.DLL",
|
||||
};
|
||||
try library.symbols.append(writer.allocator, Symbol{
|
||||
.name = "ExitProcess",
|
||||
});
|
||||
|
||||
break :blk library;
|
||||
};
|
||||
|
||||
const libraries = &[_]Library{kernel32};
|
||||
_ = libraries;
|
||||
|
||||
const code = &.{
|
||||
0x48, 0x83, 0xec, 0x28, //subq $40, %rsp
|
||||
0xb9, 0x2a, 0x00, 0x00, 0x00, //movl $42, %ecx
|
||||
0xff, 0x15, 0xf1, 0x0f, 0x00, 0x00, //callq *4081(%rip) # 0x140002000
|
||||
0xcc,
|
||||
};
|
||||
_ = code;
|
||||
|
||||
const pdata = &.{
|
||||
0x00, 0x10,
|
||||
0x00, 0x00,
|
||||
0x10, 0x10,
|
||||
0x00, 0x00,
|
||||
0x28, 0x21,
|
||||
0x00, 0x00,
|
||||
};
|
||||
_ = pdata;
|
||||
|
||||
// TODO
|
||||
// writer.append(std.mem.asBytes(ImageOptionalHeader{
|
||||
// .magic = ImageOptionalHeader.magic,
|
||||
// .size_of_code = code.len,
|
||||
// }));
|
||||
|
||||
unreachable;
|
||||
}
|
||||
|
||||
fn append(writer: *Writer, bytes: []const u8) void {
|
||||
const destination = writer.items[writer.index..][0..bytes.len];
|
||||
const source = bytes;
|
||||
@memcpy(destination, source);
|
||||
writer.index += bytes.len;
|
||||
}
|
||||
|
||||
pub fn writeToFile(writer: *Writer, executable_relative_path: []const u8) !void {
|
||||
_ = writer;
|
||||
_ = executable_relative_path;
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
const ImageDosHeader = extern struct {
|
||||
magic_number: u16 = magic,
|
||||
bytes_last_page_of_file: u16 = 0,
|
||||
pages_in_file: u16 = 0,
|
||||
relocations: u16 = 0,
|
||||
size_of_header_in_paragraphs: u16 = 0,
|
||||
minimum_extra_paragraphs: u16 = 0,
|
||||
maximum_extra_paragraphs: u16 = 0,
|
||||
initial_ss_value: u16 = 0,
|
||||
initial_sp_value: u16 = 0,
|
||||
cheksum: u16 = 0,
|
||||
initial_ip_value: u16 = 0,
|
||||
initial_cs_value: u16 = 0,
|
||||
file_address_of_relocation_table: u16 = 0,
|
||||
overlay_number: u16 = 0,
|
||||
reserved_words: [4]u16 = .{0} ** 4,
|
||||
oem_id: u16 = 0,
|
||||
oem_info: u16 = 0,
|
||||
reserved_words2: [10]u16 = .{0} ** 10,
|
||||
file_address_of_new_exe_header: u32 = @sizeOf(ImageDosHeader),
|
||||
|
||||
const magic = 0x5a4d;
|
||||
|
||||
comptime {
|
||||
assert(@sizeOf(ImageDosHeader) == 64);
|
||||
}
|
||||
};
|
||||
const image_NT_signature: u32 = 0x00004550;
|
||||
|
||||
/// COFF header format
|
||||
const ImageFileHeader = extern struct {
|
||||
machine: ImageFileMachine,
|
||||
section_count: u16,
|
||||
time_date_stamp: u32,
|
||||
symbol_table_offset: u32 = 0,
|
||||
symbol_count: u32 = 0,
|
||||
size_of_optional_header: u16 = @sizeOf(ImageOptionalHeader),
|
||||
characteristics: Characteristics = .{},
|
||||
|
||||
const Characteristics = packed struct(u16) {
|
||||
relocations_stripped: bool = false,
|
||||
executable_image: bool = true,
|
||||
stripped_line_count: bool = false,
|
||||
stripped_local_symbols: bool = false,
|
||||
aggressive_ws_trim: bool = false,
|
||||
large_address_aware: bool = true,
|
||||
reserved: u1 = 0,
|
||||
bytes_reversed_lo: bool = false,
|
||||
machine_32bit: bool = false,
|
||||
stripped_debug: bool = false,
|
||||
removable_run_from_swap: bool = false,
|
||||
net_run_from_swap: bool = false,
|
||||
system: bool = false,
|
||||
dll: bool = false,
|
||||
up_systems_only: bool = false,
|
||||
bytes_reversed_hi: bool = false,
|
||||
};
|
||||
};
|
||||
|
||||
const ImageFileMachine = enum(u16) {
|
||||
unknown = 0,
|
||||
target_host = 0x0001, // Useful for indicating we want to interact with the host and not a WoW guest.
|
||||
i386 = 0x014c, // Intel 386.
|
||||
r3000 = 0x0162, // MIPS little-endian, 0x160 big-endian
|
||||
r4000 = 0x0166, // MIPS little-endian
|
||||
r10000 = 0x0168, // MIPS little-endian
|
||||
wcemipsv2 = 0x0169, // MIPS little-endian WCE v2
|
||||
alpha = 0x0184, // Alpha_AXP
|
||||
sh3 = 0x01a2, // SH3 little-endian
|
||||
sh3dsp = 0x01a3,
|
||||
sh3e = 0x01a4, // SH3E little-endian
|
||||
sh4 = 0x01a6, // SH4 little-endian
|
||||
sh5 = 0x01a8, // SH5
|
||||
arm = 0x01c0, // ARM Little-Endian
|
||||
thumb = 0x01c2, // ARM Thumb/Thumb-2 Little-Endian
|
||||
armnt = 0x01c4, // ARM Thumb-2 Little-Endian
|
||||
am33 = 0x01d3,
|
||||
powerpc = 0x01F0, // IBM PowerPC Little-Endian
|
||||
powerpcfp = 0x01f1,
|
||||
ia64 = 0x0200, // Intel 64
|
||||
mips16 = 0x0266, // MIPS
|
||||
alpha64 = 0x0284, // ALPHA64
|
||||
mipsfpu = 0x0366, // MIPS
|
||||
mipsfpu16 = 0x0466, // MIPS
|
||||
tricore = 0x0520, // Infineon
|
||||
cef = 0x0CEF,
|
||||
ebc = 0x0EBC, // EFI Byte Code
|
||||
amd64 = 0x8664, // AMD64 (K8)
|
||||
m32r = 0x9041, // M32R little-endian
|
||||
arm64 = 0xAA64, // ARM64 Little-Endian
|
||||
cee = 0xC0EE,
|
||||
|
||||
const axp64 = ImageFileMachine.alpha64;
|
||||
};
|
||||
|
||||
const ImageOptionalHeader = extern struct {
|
||||
magic: u16 = magic,
|
||||
major_linker_version: u8 = 0,
|
||||
minor_linker_version: u8 = 0,
|
||||
size_of_code: u32,
|
||||
size_of_initialized_data: u32,
|
||||
size_of_uninitialized_data: u32,
|
||||
address_of_entry_point: u32,
|
||||
base_of_code: u32,
|
||||
image_base: u64,
|
||||
section_alignment: u32,
|
||||
file_alignment: u32,
|
||||
major_os_version: u16,
|
||||
minor_os_version: u16,
|
||||
major_image_version: u16,
|
||||
minor_image_version: u16,
|
||||
major_subsystem_version: u16,
|
||||
minor_subsystem_version: u16,
|
||||
win32_version_value: u32,
|
||||
size_of_image: u32,
|
||||
size_of_headers: u32,
|
||||
checksum: u32,
|
||||
subsystem: u16,
|
||||
dll_characteristics: u16,
|
||||
size_of_stack_reserve: u64,
|
||||
size_of_stack_commit: u64,
|
||||
size_of_heap_reserve: u64,
|
||||
size_of_heap_commit: u64,
|
||||
loader_flags: u32,
|
||||
number_of_RVA_and_sizes: u32,
|
||||
data_directory: [image_number_of_directory_entries]ImageDataDirectory,
|
||||
|
||||
const magic = 0x20b;
|
||||
|
||||
comptime {
|
||||
assert(@sizeOf(ImageOptionalHeader) == 0xf0);
|
||||
}
|
||||
};
|
||||
|
||||
const ImageDataDirectory = extern struct {
|
||||
virtual_address: u32,
|
||||
size: u32,
|
||||
};
|
||||
|
||||
const image_number_of_directory_entries = 0x10;
|
||||
|
||||
const Library = struct {
|
||||
symbols: ArrayList(Symbol) = .{},
|
||||
name: []const u8,
|
||||
name_virtual_address: u32 = 0,
|
||||
virtual_address: u32 = 0,
|
||||
image_thunk_virtual_address: u32 = 0,
|
||||
};
|
||||
|
||||
const Symbol = struct {
|
||||
name: []const u8,
|
||||
name_virtual_address: u32 = 0,
|
||||
offset_in_data: u32 = 0,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -110,11 +110,6 @@ pub fn BlockList(comptime T: type) type {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Allocation = struct {
|
||||
ptr: *T,
|
||||
index: Index,
|
||||
};
|
||||
|
||||
pub fn iterator(list: *List) Iterator {
|
||||
return .{
|
||||
.index = Index{
|
||||
@ -130,26 +125,22 @@ pub fn BlockList(comptime T: type) type {
|
||||
return &list.blocks.items[index.block].items[index.element];
|
||||
}
|
||||
|
||||
pub fn append(list: *List, allocator: Allocator, element: T) !Allocation {
|
||||
pub fn append(list: *List, allocator: Allocator, element: T) !Index {
|
||||
const result = try list.addOne(allocator);
|
||||
result.ptr.* = element;
|
||||
list.get(result).* = element;
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn addOne(list: *List, allocator: Allocator) !Allocation {
|
||||
pub fn addOne(list: *List, allocator: Allocator) !Index {
|
||||
try list.ensureCapacity(allocator, list.len + 1);
|
||||
const max_allocation = list.blocks.items.len * item_count;
|
||||
const result = switch (list.len < max_allocation) {
|
||||
true => blk: {
|
||||
const block = &list.blocks.items[list.first_block];
|
||||
if (block.allocateIndex()) |element_index| {
|
||||
const ptr = &block.items[element_index];
|
||||
break :blk Allocation{
|
||||
.ptr = ptr,
|
||||
.index = .{
|
||||
break :blk Index{
|
||||
.element = element_index,
|
||||
.block = @intCast(list.first_block),
|
||||
},
|
||||
};
|
||||
} else |_| {
|
||||
@panic("TODO");
|
||||
@ -161,13 +152,12 @@ pub fn BlockList(comptime T: type) type {
|
||||
new_block.* = .{};
|
||||
const element_index = new_block.allocateIndex() catch unreachable;
|
||||
const ptr = &new_block.items[element_index];
|
||||
_ = ptr;
|
||||
list.first_block += @intFromBool(block_index != 0);
|
||||
break :blk Allocation{
|
||||
.ptr = ptr,
|
||||
.index = .{
|
||||
|
||||
break :blk Index{
|
||||
.element = element_index,
|
||||
.block = @intCast(block_index),
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
@ -21,38 +21,12 @@ pub const Token = packed struct(u64) {
|
||||
|
||||
pub const Id = enum(u8) {
|
||||
eof = 0x00,
|
||||
identifier = 0x01,
|
||||
number_literal = 0x02,
|
||||
string_literal = 0x03,
|
||||
fixed_keyword_function = 0x04,
|
||||
fixed_keyword_const = 0x05,
|
||||
fixed_keyword_var = 0x06,
|
||||
fixed_keyword_void = 0x07,
|
||||
fixed_keyword_noreturn = 0x08,
|
||||
fixed_keyword_comptime = 0x09,
|
||||
fixed_keyword_while = 0x0a,
|
||||
fixed_keyword_bool = 0x0b,
|
||||
fixed_keyword_true = 0x0c,
|
||||
fixed_keyword_false = 0x0d,
|
||||
fixed_keyword_fn = 0x0e,
|
||||
fixed_keyword_unreachable = 0x0f,
|
||||
fixed_keyword_return = 0x10,
|
||||
fixed_keyword_ssize = 0x11,
|
||||
fixed_keyword_usize = 0x12,
|
||||
fixed_keyword_switch = 0x13,
|
||||
fixed_keyword_if = 0x14,
|
||||
fixed_keyword_else = 0x15,
|
||||
fixed_keyword_struct = 0x16,
|
||||
fixed_keyword_enum = 0x17,
|
||||
fixed_keyword_union = 0x18,
|
||||
fixed_keyword_extern = 0x19,
|
||||
fixed_keyword_null = 0x1a,
|
||||
fixed_keyword_align = 0x1b,
|
||||
fixed_keyword_export = 0x1c,
|
||||
fixed_keyword_cc = 0x1d,
|
||||
fixed_keyword_for = 0x1e,
|
||||
keyword_unsigned_integer = 0x1f,
|
||||
keyword_signed_integer = 0x20,
|
||||
keyword_unsigned_integer = 0x01,
|
||||
keyword_signed_integer = 0x02,
|
||||
identifier = 0x03,
|
||||
number_literal = 0x04,
|
||||
string_literal = 0x05,
|
||||
discard = 0x06,
|
||||
bang = '!', // 0x21
|
||||
hash = '#', // 0x23
|
||||
dollar_sign = '$', // 0x24
|
||||
@ -83,6 +57,34 @@ pub const Token = packed struct(u64) {
|
||||
vertical_bar = '|', // 0x7c
|
||||
right_brace = '}', // 0x7d
|
||||
tilde = '~', // 0x7e
|
||||
fixed_keyword_function = 0x7f,
|
||||
fixed_keyword_const = 0x80,
|
||||
fixed_keyword_var = 0x81,
|
||||
fixed_keyword_void = 0x82,
|
||||
fixed_keyword_noreturn = 0x83,
|
||||
fixed_keyword_comptime = 0x84,
|
||||
fixed_keyword_while = 0x85,
|
||||
fixed_keyword_bool = 0x86,
|
||||
fixed_keyword_true = 0x87,
|
||||
fixed_keyword_false = 0x88,
|
||||
fixed_keyword_fn = 0x89,
|
||||
fixed_keyword_unreachable = 0x8a,
|
||||
fixed_keyword_return = 0x8b,
|
||||
fixed_keyword_ssize = 0x8c,
|
||||
fixed_keyword_usize = 0x8d,
|
||||
fixed_keyword_switch = 0x8e,
|
||||
fixed_keyword_if = 0x8f,
|
||||
fixed_keyword_else = 0x90,
|
||||
fixed_keyword_struct = 0x91,
|
||||
fixed_keyword_enum = 0x92,
|
||||
fixed_keyword_union = 0x93,
|
||||
fixed_keyword_extern = 0x94,
|
||||
fixed_keyword_null = 0x95,
|
||||
fixed_keyword_align = 0x96,
|
||||
fixed_keyword_export = 0x97,
|
||||
fixed_keyword_cc = 0x98,
|
||||
fixed_keyword_for = 0x99,
|
||||
fixed_keyword_undefined = 0x9a,
|
||||
};
|
||||
|
||||
pub const Index = u32;
|
||||
@ -116,6 +118,7 @@ pub const FixedKeyword = enum {
|
||||
@"export",
|
||||
cc,
|
||||
@"for",
|
||||
undefined,
|
||||
};
|
||||
|
||||
pub const Result = struct {
|
||||
@ -175,9 +178,10 @@ pub fn analyze(allocator: Allocator, text: []const u8, file_index: File.Index) !
|
||||
}
|
||||
}
|
||||
|
||||
break :blk if (enumFromString(FixedKeyword, text[start_index..][0 .. index - start_index])) |fixed_keyword| switch (fixed_keyword) {
|
||||
const string = text[start_index..][0 .. index - start_index];
|
||||
break :blk if (enumFromString(FixedKeyword, string)) |fixed_keyword| switch (fixed_keyword) {
|
||||
inline else => |comptime_fixed_keyword| @field(Token.Id, "fixed_keyword_" ++ @tagName(comptime_fixed_keyword)),
|
||||
} else .identifier;
|
||||
} else if (equal(u8, string, "_")) .discard else .identifier;
|
||||
},
|
||||
'0'...'9' => blk: {
|
||||
// Detect other non-decimal literals
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -115,6 +115,7 @@ pub const Node = struct {
|
||||
unsigned_integer_type,
|
||||
signed_integer_type,
|
||||
slice_type,
|
||||
array_type,
|
||||
argument_declaration,
|
||||
compiler_intrinsic,
|
||||
ssize_type,
|
||||
@ -123,6 +124,8 @@ pub const Node = struct {
|
||||
call,
|
||||
const_many_pointer_type,
|
||||
many_pointer_type,
|
||||
zero_terminated_const_many_pointer_type,
|
||||
zero_terminated_many_pointer_type,
|
||||
enum_literal,
|
||||
address_of,
|
||||
pointer_dereference,
|
||||
@ -178,6 +181,7 @@ pub const Node = struct {
|
||||
for_condition,
|
||||
for_loop,
|
||||
add_assign,
|
||||
undefined,
|
||||
};
|
||||
};
|
||||
|
||||
@ -446,13 +450,18 @@ const Analyzer = struct {
|
||||
},
|
||||
else => try analyzer.assignExpressionStatement(),
|
||||
},
|
||||
.fixed_keyword_unreachable, .fixed_keyword_return => try analyzer.assignExpressionStatement(),
|
||||
.fixed_keyword_unreachable,
|
||||
.fixed_keyword_return,
|
||||
.discard,
|
||||
=> try analyzer.assignExpressionStatement(),
|
||||
|
||||
.fixed_keyword_while => try analyzer.whileExpression(options),
|
||||
.fixed_keyword_switch => try analyzer.switchExpression(),
|
||||
.fixed_keyword_if => try analyzer.ifExpression(),
|
||||
.fixed_keyword_for => try analyzer.forExpression(),
|
||||
.fixed_keyword_const, .fixed_keyword_var => try analyzer.symbolDeclaration(),
|
||||
.fixed_keyword_const,
|
||||
.fixed_keyword_var,
|
||||
=> try analyzer.symbolDeclaration(),
|
||||
.hash => blk: {
|
||||
const intrinsic = try analyzer.compilerIntrinsic();
|
||||
_ = try analyzer.expectToken(.semicolon);
|
||||
@ -581,9 +590,13 @@ const Analyzer = struct {
|
||||
|
||||
const payload = if (analyzer.tokens[analyzer.token_i].id == .vertical_bar) blk: {
|
||||
analyzer.token_i += 1;
|
||||
const payload_identifier_node = try analyzer.identifierNode();
|
||||
const payload_node = switch (analyzer.tokens[analyzer.token_i].id) {
|
||||
.identifier => try analyzer.identifierNode(),
|
||||
.discard => try analyzer.discardNode(),
|
||||
else => unreachable,
|
||||
};
|
||||
_ = try analyzer.expectToken(.vertical_bar);
|
||||
break :blk payload_identifier_node;
|
||||
break :blk payload_node;
|
||||
} else Node.Index.invalid;
|
||||
|
||||
const if_block = try analyzer.block(.{ .is_comptime = false });
|
||||
@ -660,7 +673,14 @@ const Analyzer = struct {
|
||||
|
||||
var payload_nodes = ArrayList(Node.Index){};
|
||||
while (analyzer.tokens[analyzer.token_i].id != .vertical_bar) {
|
||||
const payload_identifier = try analyzer.expectToken(.identifier);
|
||||
const payload_token = analyzer.token_i;
|
||||
const id: Node.Id = switch (analyzer.tokens[payload_token].id) {
|
||||
.identifier => .identifier,
|
||||
.discard => .discard,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
analyzer.token_i += 1;
|
||||
|
||||
switch (analyzer.tokens[analyzer.token_i].id) {
|
||||
.vertical_bar => {},
|
||||
@ -669,8 +689,8 @@ const Analyzer = struct {
|
||||
}
|
||||
|
||||
try payload_nodes.append(analyzer.allocator, try analyzer.addNode(.{
|
||||
.id = .identifier,
|
||||
.token = payload_identifier,
|
||||
.id = id,
|
||||
.token = payload_token,
|
||||
.left = Node.Index.invalid,
|
||||
.right = Node.Index.invalid,
|
||||
}));
|
||||
@ -1105,6 +1125,8 @@ const Analyzer = struct {
|
||||
.keyword_unsigned_integer,
|
||||
.fixed_keyword_enum,
|
||||
.fixed_keyword_struct,
|
||||
.discard,
|
||||
.fixed_keyword_undefined,
|
||||
=> try analyzer.curlySuffixExpression(),
|
||||
.fixed_keyword_fn => try analyzer.function(),
|
||||
.fixed_keyword_return => try analyzer.addNode(.{
|
||||
@ -1168,6 +1190,7 @@ 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;
|
||||
@ -1181,13 +1204,22 @@ const Analyzer = struct {
|
||||
}
|
||||
|
||||
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,
|
||||
@ -1224,11 +1256,19 @@ const Analyzer = struct {
|
||||
.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,
|
||||
});
|
||||
},
|
||||
.asterisk => @panic("Meant to use ampersand?"),
|
||||
@ -1236,25 +1276,38 @@ const Analyzer = struct {
|
||||
const left_bracket = analyzer.token_i;
|
||||
analyzer.token_i += 1;
|
||||
// TODO: compute length
|
||||
const length_expression = false;
|
||||
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);
|
||||
|
||||
// Slice
|
||||
if (!length_expression) {
|
||||
// TODO: modifiers
|
||||
const is_const = analyzer.tokens[analyzer.token_i].id == .fixed_keyword_const;
|
||||
analyzer.token_i += @intFromBool(is_const);
|
||||
switch (length_expression.invalid) {
|
||||
true => analyzer.token_i += @intFromBool(analyzer.tokens[analyzer.token_i].id == .fixed_keyword_const),
|
||||
false => {},
|
||||
}
|
||||
|
||||
const slice_type = try analyzer.typeExpression();
|
||||
return try analyzer.addNode(.{
|
||||
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 = .slice_type,
|
||||
.token = left_bracket,
|
||||
.left = Node.Index.invalid,
|
||||
.right = slice_type,
|
||||
});
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
.right = type_expression,
|
||||
},
|
||||
};
|
||||
|
||||
const node_index = try analyzer.addNode(node);
|
||||
|
||||
return node_index;
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -1359,6 +1412,18 @@ const Analyzer = struct {
|
||||
return try analyzer.nodeList(list);
|
||||
}
|
||||
|
||||
fn discardNode(analyzer: *Analyzer) !Node.Index {
|
||||
const token = analyzer.token_i;
|
||||
assert(analyzer.tokens[token].id == .discard);
|
||||
analyzer.token_i += 1;
|
||||
return try analyzer.addNode(.{
|
||||
.id = .discard,
|
||||
.token = token,
|
||||
.left = Node.Index.invalid,
|
||||
.right = Node.Index.invalid,
|
||||
});
|
||||
}
|
||||
|
||||
fn primaryTypeExpression(analyzer: *Analyzer) anyerror!Node.Index {
|
||||
const token_i = analyzer.token_i;
|
||||
const token = analyzer.tokens[token_i];
|
||||
@ -1387,8 +1452,18 @@ const Analyzer = struct {
|
||||
});
|
||||
},
|
||||
.identifier => analyzer.identifierNode(),
|
||||
.discard => try analyzer.discardNode(),
|
||||
.fixed_keyword_noreturn => analyzer.noReturn(),
|
||||
.fixed_keyword_true, .fixed_keyword_false => analyzer.boolLiteral(),
|
||||
.fixed_keyword_undefined => analyzer.addNode(.{
|
||||
.id = .undefined,
|
||||
.token = blk: {
|
||||
analyzer.token_i += 1;
|
||||
break :blk token_i;
|
||||
},
|
||||
.left = Node.Index.invalid,
|
||||
.right = Node.Index.invalid,
|
||||
}),
|
||||
.fixed_keyword_null => analyzer.addNode(.{
|
||||
.id = .null_literal,
|
||||
.token = blk: {
|
||||
@ -1653,10 +1728,8 @@ const Analyzer = struct {
|
||||
const identifier_token = analyzer.token_i;
|
||||
assert(analyzer.tokens[identifier_token].id == .identifier);
|
||||
analyzer.token_i += 1;
|
||||
const identifier = analyzer.bytes(identifier_token);
|
||||
// logln("identifier: {s}", .{identifier});
|
||||
return try analyzer.addNode(.{
|
||||
.id = if (equal(u8, identifier, "_")) .discard else .identifier,
|
||||
.id = .identifier,
|
||||
.token = identifier_token,
|
||||
.left = Node.Index.invalid,
|
||||
.right = Node.Index.invalid,
|
||||
|
@ -7,7 +7,7 @@ pub fn build(b: *std.Build) !void {
|
||||
const optimization = b.standardOptimizeOption(.{});
|
||||
const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse true;
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "nativity",
|
||||
.name = "nat",
|
||||
.root_source_file = .{ .path = "bootstrap/main.zig" },
|
||||
.target = target,
|
||||
.optimize = optimization,
|
||||
@ -25,6 +25,7 @@ pub fn build(b: *std.Build) !void {
|
||||
});
|
||||
|
||||
const run_command = b.addRunArtifact(exe);
|
||||
run_command.step.dependOn(b.getInstallStep());
|
||||
|
||||
const debug_command = switch (@import("builtin").os.tag) {
|
||||
.linux => blk: {
|
||||
|
34
ci.sh
34
ci.sh
@ -19,51 +19,65 @@ failed_tests=()
|
||||
for dir in $test_directory
|
||||
do
|
||||
MY_TESTNAME=${dir##*/}
|
||||
zig build run -Duse_llvm=$nativity_use_llvm -- $dir/main.nat -log ir
|
||||
zig build run -Duse_llvm=$nativity_use_llvm -- $dir/main.nat
|
||||
|
||||
if [[ "$?" == "0" ]]; then
|
||||
passed_compilation_count=$(($passed_compilation_count + 1))
|
||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
nat/$MY_TESTNAME
|
||||
|
||||
if [[ "$?" == "0" ]]; then
|
||||
passed_test_count=$(($passed_test_count + 1))
|
||||
result="PASSED"
|
||||
result="\e[32mPASSED\e[0m"
|
||||
else
|
||||
failed_test_count=$(($failed_test_count + 1))
|
||||
result="FAILED"
|
||||
result="\e[31mFAILED\e[0m"
|
||||
failed_tests+=("$test_i. $MY_TESTNAME")
|
||||
fi
|
||||
echo "[$test_i/$total_test_count] [$result] $MY_TESTNAME"
|
||||
|
||||
ran_test_count=$(($ran_test_count + 1))
|
||||
else
|
||||
result="\e[31mOS NOT SUPPORTED\e[0m"
|
||||
fi
|
||||
else
|
||||
failed_compilation_count=$(($failed_compilation_count + 1))
|
||||
echo "$MY_TESTNAME failed to compile"
|
||||
result="\e[31mCOMPILATION FAILURE\e[0m"
|
||||
failed_compilations+=("$test_i. $MY_TESTNAME")
|
||||
fi
|
||||
|
||||
echo -e "[$test_i/$total_test_count] [$result] $MY_TESTNAME"
|
||||
|
||||
test_i=$(($test_i + 1))
|
||||
done
|
||||
|
||||
echo "Ran $total_test_count compilations ($passed_compilation_count succeeded, $failed_compilation_count failed)."
|
||||
echo "Ran $ran_test_count tests ($passed_test_count passed, $failed_test_count failed)."
|
||||
printf "\n"
|
||||
echo "[SUMMARY]"
|
||||
echo "========="
|
||||
echo -e "Ran $total_test_count compilations (\e[32m$passed_compilation_count\e[0m succeeded, \e[31m$failed_compilation_count\e[0m failed)."
|
||||
echo -e "Ran $ran_test_count tests (\e[32m $passed_test_count\e[0m passed, \e[31m$failed_test_count\e[0m failed)."
|
||||
|
||||
if [[ "$failed_compilation_count" != "0" ]]; then
|
||||
echo "Failed compilations:"
|
||||
printf $"\nFailed compilations:\n"
|
||||
for failed_compilation in "${failed_compilations[@]}"
|
||||
do
|
||||
echo "$failed_compilation"
|
||||
echo -e "\e[31m$failed_compilation\e[0m"
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
if [[ "$failed_test_count" != "0" ]]; then
|
||||
echo $'\n'
|
||||
echo "Failed tests:"
|
||||
for failed_test in "${failed_tests[@]}"
|
||||
do
|
||||
echo "$failed_test"
|
||||
echo -e "\e[31m$failed_test\e[0m"
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ "$failed_test_count" == "0" && "$failed_compilation_count" == "0" ]]; then
|
||||
echo -e "\e[32mSUCCESS!\e[0m"
|
||||
true
|
||||
else
|
||||
echo -e "\e[31mFAILURE!\e[0m"
|
||||
false
|
||||
fi
|
||||
|
@ -1,3 +1,5 @@
|
||||
const std = #import("std");
|
||||
const Allocator = std.Allocator;
|
||||
const current = #import("builtin").os;
|
||||
const system = switch (current) {
|
||||
.linux => linux,
|
||||
@ -56,21 +58,70 @@ const allocate_virtual_memory = fn(address: ?[&]u8, length: usize, general_prote
|
||||
const protection_flags = system.get_protection_flags(flags = general_protection_flags);
|
||||
const map_flags = system.get_map_flags(flags = general_map_flags);
|
||||
|
||||
const result = switch (#import("builtin").os) {
|
||||
.linux => linux.mmap(address, length, protection_flags, map_flags, fd = -1, offset = 0),
|
||||
switch (current) {
|
||||
.linux => {
|
||||
if (linux.unwrapSyscall(syscall_result = linux.mmap(address, length, protection_flags, map_flags, fd = -1, offset = 0))) |result_address| {
|
||||
const pointer: [&]u8 = #cast(result_address);
|
||||
return pointer;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
else => #error("OS not supported"),
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const free_virtual_memory = fn(bytes_ptr: [&]const u8, bytes_len: usize) bool {
|
||||
const result = switch (#import("builtin").os) {
|
||||
.linux => linux.munmap(bytes_ptr, bytes_len),
|
||||
switch (current) {
|
||||
.linux => {
|
||||
if (linux.unwrapSyscall(syscall_result = linux.munmap(bytes_ptr, bytes_len))) |result| {
|
||||
return result == 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
else => #error("OS not supported"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const readlink = fn(file_path: [&:0]const u8, buffer: []u8) ?[]u8 {
|
||||
switch (current) {
|
||||
.linux => {
|
||||
const raw_result = linux.readlink(file_path, bytes_ptr = buffer.ptr, bytes_len = buffer.len);
|
||||
|
||||
if (linux.unwrapSyscall(syscall_result = raw_result)) |byte_count| {
|
||||
const bytes = buffer[0..byte_count];
|
||||
return bytes;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
else => #error("OS not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
const max_path_byte_count = switch (current) {
|
||||
.linux => 0x1000,
|
||||
else => #error("OS not supported"),
|
||||
};
|
||||
|
||||
const currentExecutablePath = fn(allocator: &Allocator) ?[]u8 {
|
||||
switch (current) {
|
||||
.linux => {
|
||||
var buffer: [max_path_byte_count]u8 = undefined;
|
||||
if (readlink(file_path = "/proc/self/exe", buffer = buffer.&)) |bytes| {
|
||||
if (allocator.duplicateBytes(bytes)) |result| {
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
else => #error("OS not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
const linux = #import("os/linux.nat");
|
||||
|
@ -33,12 +33,26 @@ const get_map_flags = fn(flags: std.os.MapFlags) MapFlags{
|
||||
};
|
||||
}
|
||||
|
||||
const mmap = fn(address: ?[&]u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, fd: s32, offset: u64) ?[&]u8 {
|
||||
const mmap = fn(address: ?[&]u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, fd: s32, offset: u64) usize {
|
||||
const result = #syscall(9, #cast(address), length, #cast(protection_flags), #cast(map_flags), fd, offset);
|
||||
return #cast(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
const munmap = fn(bytes_ptr: [&]const u8, bytes_len: usize) bool {
|
||||
const result: ssize = #syscall(11, #cast(bytes_ptr), bytes_len);
|
||||
return result == 0;
|
||||
const munmap = fn(bytes_ptr: [&]const u8, bytes_len: usize) usize {
|
||||
const result = #syscall(11, #cast(bytes_ptr), bytes_len);
|
||||
return result;
|
||||
}
|
||||
|
||||
const readlink = fn(file_path: [&:0]const u8, bytes_ptr: [&]u8, bytes_len: usize) usize {
|
||||
const result = #syscall(89, #cast(file_path), #cast(bytes_ptr), bytes_len);
|
||||
return result;
|
||||
}
|
||||
|
||||
const unwrapSyscall = fn(syscall_result: usize) ?usize {
|
||||
const signed_syscall_result: ssize = #cast(syscall_result);
|
||||
if (signed_syscall_result >= 0) {
|
||||
return syscall_result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,15 @@ const Allocator = struct {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const duplicateBytes = fn (allocator: &Allocator, bytes: []const u8) ?[]u8 {
|
||||
if (allocator.allocate(size = bytes.len, alignment = 0)) |result| {
|
||||
copyBytes(destination = result, source = bytes);
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const PageAllocator = struct{
|
||||
@ -85,4 +94,11 @@ const PageAllocator = struct{
|
||||
}
|
||||
};
|
||||
|
||||
const copyBytes = fn(destination: []u8, source: []const u8) void {
|
||||
assert(ok = destination.len == source.len);
|
||||
for (0..destination.len) |i| {
|
||||
destination[i] = source[i];
|
||||
}
|
||||
}
|
||||
|
||||
var page_allocator = PageAllocator{};
|
||||
|
13
test/self_exe_path/main.nat
Normal file
13
test/self_exe_path/main.nat
Normal file
@ -0,0 +1,13 @@
|
||||
const std = #import("std");
|
||||
const print = std.print;
|
||||
|
||||
const main = fn () s32 {
|
||||
if (std.os.currentExecutablePath(allocator = std.page_allocator.allocator.&)) |result| {
|
||||
print(bytes_ptr = result.ptr, bytes_len = result.len);
|
||||
print(bytes_ptr = "\n", bytes_len = 1);
|
||||
return 0;
|
||||
} else {
|
||||
print(bytes_ptr = "Failed\n", bytes_len = 7);
|
||||
return 1;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user