implement basic builder
This commit is contained in:
parent
57325e4530
commit
8a042c58e5
@ -54,6 +54,7 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
|||||||
var maybe_main_package_path: ?[]const u8 = null;
|
var maybe_main_package_path: ?[]const u8 = null;
|
||||||
var target_triplet: []const u8 = "x86_64-linux-gnu";
|
var target_triplet: []const u8 = "x86_64-linux-gnu";
|
||||||
var should_transpile_to_c: ?bool = null;
|
var should_transpile_to_c: ?bool = null;
|
||||||
|
var maybe_only_parse: ?bool = null;
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < arguments.len) : (i += 1) {
|
while (i < arguments.len) : (i += 1) {
|
||||||
@ -128,6 +129,16 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
|||||||
} else {
|
} else {
|
||||||
reportUnterminatedArgumentError(current_argument);
|
reportUnterminatedArgumentError(current_argument);
|
||||||
}
|
}
|
||||||
|
} else if (equal(u8, current_argument, "-parse")) {
|
||||||
|
if (i + 1 != arguments.len) {
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
const arg = arguments[i];
|
||||||
|
maybe_main_package_path = arg;
|
||||||
|
maybe_only_parse = true;
|
||||||
|
} else {
|
||||||
|
reportUnterminatedArgumentError(current_argument);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
maybe_main_package_path = current_argument;
|
maybe_main_package_path = current_argument;
|
||||||
}
|
}
|
||||||
@ -136,6 +147,7 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
|||||||
const cross_target = try std.zig.CrossTarget.parse(.{ .arch_os_abi = target_triplet });
|
const cross_target = try std.zig.CrossTarget.parse(.{ .arch_os_abi = target_triplet });
|
||||||
const target = cross_target.toTarget();
|
const target = cross_target.toTarget();
|
||||||
const transpile_to_c = should_transpile_to_c orelse true;
|
const transpile_to_c = should_transpile_to_c orelse true;
|
||||||
|
const only_parse = maybe_only_parse orelse false;
|
||||||
|
|
||||||
var is_build = false;
|
var is_build = false;
|
||||||
const main_package_path = if (maybe_main_package_path) |path| path else blk: {
|
const main_package_path = if (maybe_main_package_path) |path| path else blk: {
|
||||||
@ -160,6 +172,7 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
|||||||
.target = target,
|
.target = target,
|
||||||
.transpile_to_c = transpile_to_c,
|
.transpile_to_c = transpile_to_c,
|
||||||
.is_build = is_build,
|
.is_build = is_build,
|
||||||
|
.only_parse = only_parse,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,24 +224,6 @@ pub const ContainerInitialization = struct {
|
|||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Enum = struct {
|
|
||||||
scope: Scope.Index,
|
|
||||||
fields: ArrayList(Enum.Field.Index) = .{},
|
|
||||||
backing_type: Type.Index,
|
|
||||||
|
|
||||||
pub const Field = struct {
|
|
||||||
name: u32,
|
|
||||||
value: Value.Index,
|
|
||||||
parent: Type.Index,
|
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
|
||||||
pub const Index = Enum.Field.List.Index;
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
|
||||||
pub const Index = List.Index;
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Type = union(enum) {
|
pub const Type = union(enum) {
|
||||||
any,
|
any,
|
||||||
void,
|
void,
|
||||||
@ -277,6 +272,24 @@ pub const Type = union(enum) {
|
|||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
|
||||||
|
pub const Enum = struct {
|
||||||
|
scope: Scope.Index,
|
||||||
|
fields: ArrayList(Enum.Field.Index) = .{},
|
||||||
|
backing_type: Type.Index,
|
||||||
|
|
||||||
|
pub const Field = struct {
|
||||||
|
name: u32,
|
||||||
|
value: Value.Index,
|
||||||
|
parent: Type.Index,
|
||||||
|
|
||||||
|
pub const List = BlockList(@This());
|
||||||
|
pub const Index = Enum.Field.List.Index;
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const List = BlockList(@This());
|
||||||
|
pub const Index = Enum.List.Index;
|
||||||
|
};
|
||||||
|
|
||||||
pub const Integer = struct {
|
pub const Integer = struct {
|
||||||
bit_count: u16,
|
bit_count: u16,
|
||||||
signedness: Signedness,
|
signedness: Signedness,
|
||||||
@ -365,13 +378,40 @@ pub const Type = union(enum) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Intrinsic = struct {
|
||||||
|
kind: Kind,
|
||||||
|
type: Type.Index,
|
||||||
|
|
||||||
|
pub const Kind = union(enum) {
|
||||||
|
cast: Value.Index,
|
||||||
|
array_coerce_to_slice: Value.Index,
|
||||||
|
min: Binary,
|
||||||
|
optional_wrap: Value.Index,
|
||||||
|
optional_unwrap: Value.Index,
|
||||||
|
optional_check: Value.Index,
|
||||||
|
sign_extend: Value.Index,
|
||||||
|
syscall: ArrayList(Value.Index),
|
||||||
|
zero_extend: Value.Index,
|
||||||
|
|
||||||
|
pub const Binary = struct {
|
||||||
|
left: Value.Index,
|
||||||
|
right: Value.Index,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const List = BlockList(@This());
|
||||||
|
pub const Index = @This().List.Index;
|
||||||
|
};
|
||||||
|
|
||||||
// Each time an enum is added here, a corresponding insertion in the initialization must be made
|
// Each time an enum is added here, a corresponding insertion in the initialization must be made
|
||||||
pub const Intrinsic = enum {
|
pub const ValidIntrinsic = enum {
|
||||||
//@"asm", this is processed separately as it need special parsing
|
//@"asm", this is processed separately as it need special parsing
|
||||||
|
cast,
|
||||||
@"error",
|
@"error",
|
||||||
import,
|
import,
|
||||||
|
min,
|
||||||
|
size,
|
||||||
syscall,
|
syscall,
|
||||||
cast,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const FixedTypeKeyword = enum {
|
pub const FixedTypeKeyword = enum {
|
||||||
@ -460,14 +500,36 @@ pub const Declaration = struct {
|
|||||||
init_value: Value.Index,
|
init_value: Value.Index,
|
||||||
name: u32,
|
name: u32,
|
||||||
argument_index: ?u32,
|
argument_index: ?u32,
|
||||||
type: Type.Index,
|
// A union is needed here because of global lazy declarations
|
||||||
|
type: Declaration.Type,
|
||||||
scope: Scope.Index,
|
scope: Scope.Index,
|
||||||
|
|
||||||
pub const Reference = struct {
|
pub const Reference = struct {
|
||||||
value: Declaration.Index,
|
value: Declaration.Index,
|
||||||
type: Type.Index,
|
|
||||||
|
pub fn getType(reference: Reference, module: *Module) Compilation.Type.Index {
|
||||||
|
return module.values.declarations.get(reference.value).getType();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Type = union(enum) {
|
||||||
|
resolved: Compilation.Type.Index,
|
||||||
|
inferred: Compilation.Type.Index,
|
||||||
|
unresolved: Node.Index,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn getType(declaration: *Declaration) Compilation.Type.Index {
|
||||||
|
const type_index: Compilation.Type.Index = switch (declaration.type) {
|
||||||
|
.resolved => |resolved| resolved,
|
||||||
|
.inferred => |inferred| inferred,
|
||||||
|
.unresolved => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(!type_index.invalid);
|
||||||
|
|
||||||
|
return type_index;
|
||||||
|
}
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
};
|
};
|
||||||
@ -478,7 +540,7 @@ pub const Function = struct {
|
|||||||
prototype: Type.Index,
|
prototype: Type.Index,
|
||||||
|
|
||||||
pub const Prototype = struct {
|
pub const Prototype = struct {
|
||||||
arguments: ?[]const Declaration.Index,
|
arguments: ArrayList(Declaration.Index),
|
||||||
return_type: Type.Index,
|
return_type: Type.Index,
|
||||||
attributes: Attributes = .{},
|
attributes: Attributes = .{},
|
||||||
|
|
||||||
@ -610,6 +672,7 @@ pub const BinaryOperation = struct {
|
|||||||
compare_greater_or_equal,
|
compare_greater_or_equal,
|
||||||
compare_less_than,
|
compare_less_than,
|
||||||
compare_less_or_equal,
|
compare_less_or_equal,
|
||||||
|
compare_not_equal,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -644,6 +707,19 @@ pub const Branch = struct {
|
|||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Switch = struct {
|
||||||
|
value: Value.Index,
|
||||||
|
groups: ArrayList(Group),
|
||||||
|
|
||||||
|
pub const Group = struct {
|
||||||
|
conditions: ArrayList(Value.Index),
|
||||||
|
expression: Value.Index,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const List = BlockList(@This());
|
||||||
|
pub const Index = List.Index;
|
||||||
|
};
|
||||||
|
|
||||||
pub const FieldAccess = struct {
|
pub const FieldAccess = struct {
|
||||||
declaration_reference: Value.Index,
|
declaration_reference: Value.Index,
|
||||||
field: ContainerField.Index,
|
field: ContainerField.Index,
|
||||||
@ -728,12 +804,14 @@ pub const Assembly = struct {
|
|||||||
pub const Instruction = enum {
|
pub const Instruction = enum {
|
||||||
@"and",
|
@"and",
|
||||||
call,
|
call,
|
||||||
|
mov,
|
||||||
xor,
|
xor,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Register = enum {
|
pub const Register = enum {
|
||||||
ebp,
|
ebp,
|
||||||
rsp,
|
rsp,
|
||||||
|
rdi,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -745,12 +823,14 @@ pub const StringLiteral = struct {
|
|||||||
|
|
||||||
pub const Value = union(enum) {
|
pub const Value = union(enum) {
|
||||||
void,
|
void,
|
||||||
bool: bool,
|
@"break",
|
||||||
undefined,
|
undefined,
|
||||||
@"unreachable",
|
@"unreachable",
|
||||||
|
bool: bool,
|
||||||
pointer_null_literal,
|
pointer_null_literal,
|
||||||
optional_null_literal,
|
optional_null_literal,
|
||||||
unresolved: Unresolved,
|
unresolved: Unresolved,
|
||||||
|
intrinsic: Intrinsic.Index,
|
||||||
declaration: Declaration.Index,
|
declaration: Declaration.Index,
|
||||||
declaration_reference: Declaration.Reference,
|
declaration_reference: Declaration.Reference,
|
||||||
loop: Loop.Index,
|
loop: Loop.Index,
|
||||||
@ -760,20 +840,16 @@ pub const Value = union(enum) {
|
|||||||
assign: Assignment.Index,
|
assign: Assignment.Index,
|
||||||
type: Type.Index,
|
type: Type.Index,
|
||||||
integer: Integer,
|
integer: Integer,
|
||||||
syscall: Syscall.Index,
|
|
||||||
call: Call.Index,
|
call: Call.Index,
|
||||||
argument_list: ArgumentList,
|
argument_list: ArgumentList,
|
||||||
@"return": Return.Index,
|
@"return": Return.Index,
|
||||||
argument: Declaration.Index,
|
argument: Declaration.Index,
|
||||||
string_literal: StringLiteral,
|
string_literal: StringLiteral,
|
||||||
enum_field: Enum.Field.Index,
|
enum_field: Type.Enum.Field.Index,
|
||||||
extern_function: Function.Prototype.Index,
|
extern_function: Function.Prototype.Index,
|
||||||
sign_extend: Cast.Index,
|
|
||||||
zero_extend: Cast.Index,
|
|
||||||
binary_operation: BinaryOperation.Index,
|
binary_operation: BinaryOperation.Index,
|
||||||
unary_operation: UnaryOperation.Index,
|
unary_operation: UnaryOperation.Index,
|
||||||
branch: Branch.Index,
|
branch: Branch.Index,
|
||||||
cast: Cast.Index,
|
|
||||||
container_initialization: ContainerInitialization.Index,
|
container_initialization: ContainerInitialization.Index,
|
||||||
array_initialization: ContainerInitialization.Index,
|
array_initialization: ContainerInitialization.Index,
|
||||||
field_access: FieldAccess.Index,
|
field_access: FieldAccess.Index,
|
||||||
@ -781,10 +857,11 @@ pub const Value = union(enum) {
|
|||||||
indexed_access: IndexedAccess.Index,
|
indexed_access: IndexedAccess.Index,
|
||||||
optional_check: OptionalCheck.Index,
|
optional_check: OptionalCheck.Index,
|
||||||
optional_unwrap: OptionalUnwrap.Index,
|
optional_unwrap: OptionalUnwrap.Index,
|
||||||
optional_cast: Cast.Index,
|
// optional_cast: Cast.Index,
|
||||||
array_coerce_to_slice: Cast.Index,
|
array_coerce_to_slice: Cast.Index,
|
||||||
slice: Slice.Index,
|
slice: Slice.Index,
|
||||||
assembly_block: Assembly.Block.Index,
|
assembly_block: Assembly.Block.Index,
|
||||||
|
switch_expression: Switch.Index,
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
@ -800,20 +877,26 @@ pub const Value = union(enum) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn isComptime(value: *Value, module: *Module) bool {
|
pub fn isComptime(value: *Value, module: *Module) bool {
|
||||||
|
_ = module;
|
||||||
|
|
||||||
return switch (value.*) {
|
return switch (value.*) {
|
||||||
.integer => |integer| integer.type.eq(Type.comptime_int),
|
.integer => |integer| integer.type.eq(Type.comptime_int),
|
||||||
.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),
|
.declaration_reference => false,
|
||||||
.bool, .void, .undefined, .function_definition, .type, .enum_field => true,
|
.bool, .void, .function_definition, .type, .enum_field => true,
|
||||||
// TODO:
|
// TODO:
|
||||||
.call,
|
.call,
|
||||||
.syscall,
|
// .syscall,
|
||||||
.binary_operation,
|
.binary_operation,
|
||||||
.container_initialization,
|
.container_initialization,
|
||||||
.cast,
|
// .cast,
|
||||||
.optional_unwrap,
|
.optional_unwrap,
|
||||||
.pointer_null_literal,
|
.pointer_null_literal,
|
||||||
.indexed_access,
|
.indexed_access,
|
||||||
.slice,
|
.slice,
|
||||||
|
.array_initialization,
|
||||||
|
.undefined,
|
||||||
|
.intrinsic,
|
||||||
|
.field_access,
|
||||||
=> false,
|
=> false,
|
||||||
// TODO:
|
// TODO:
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
@ -824,7 +907,7 @@ pub const Value = union(enum) {
|
|||||||
const result = switch (value) {
|
const result = switch (value) {
|
||||||
.call => |call_index| module.values.calls.get(call_index).type,
|
.call => |call_index| module.values.calls.get(call_index).type,
|
||||||
.integer => |integer| integer.type,
|
.integer => |integer| integer.type,
|
||||||
.declaration_reference => |declaration_reference| declaration_reference.type,
|
.declaration_reference => |declaration_reference| declaration_reference.getType(module),
|
||||||
.string_literal => |string_literal| string_literal.type,
|
.string_literal => |string_literal| string_literal.type,
|
||||||
.type => Type.type,
|
.type => Type.type,
|
||||||
.enum_field => |enum_field_index| module.types.enum_fields.get(enum_field_index).parent,
|
.enum_field => |enum_field_index| module.types.enum_fields.get(enum_field_index).parent,
|
||||||
@ -832,19 +915,18 @@ pub const Value = union(enum) {
|
|||||||
.function_declaration => |function_index| module.types.function_declarations.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,
|
.binary_operation => |binary_operation| module.values.binary_operations.get(binary_operation).type,
|
||||||
.bool => Type.boolean,
|
.bool => Type.boolean,
|
||||||
.declaration => Type.void,
|
// .declaration => Type.void,
|
||||||
.container_initialization,
|
.container_initialization,
|
||||||
.array_initialization,
|
.array_initialization,
|
||||||
=> |initialization| module.values.container_initializations.get(initialization).type,
|
=> |initialization| module.values.container_initializations.get(initialization).type,
|
||||||
.syscall => Type.usize,
|
.intrinsic => |intrinsic_index| module.values.intrinsics.get(intrinsic_index).type,
|
||||||
.unary_operation => |unary_operation_index| module.values.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,
|
.pointer_null_literal => semantic_analyzer.optional_pointer_to_any_type,
|
||||||
.optional_null_literal => semantic_analyzer.optional_any,
|
.optional_null_literal => semantic_analyzer.optional_any,
|
||||||
.field_access => |field_access_index| module.types.container_fields.get(module.values.field_accesses.get(field_access_index).field).type,
|
.field_access => |field_access_index| module.types.container_fields.get(module.values.field_accesses.get(field_access_index).field).type,
|
||||||
.cast,
|
// .cast,
|
||||||
.optional_cast,
|
// .optional_cast,
|
||||||
.array_coerce_to_slice,
|
// .array_coerce_to_slice => |cast_index| module.values.casts.get(cast_index).type,
|
||||||
=> |cast_index| module.values.casts.get(cast_index).type,
|
|
||||||
.slice => |slice_index| module.values.slices.get(slice_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,
|
.slice_access => |slice_access_index| module.values.slice_accesses.get(slice_access_index).type,
|
||||||
.optional_check => Type.boolean,
|
.optional_check => Type.boolean,
|
||||||
@ -854,6 +936,22 @@ pub const Value = union(enum) {
|
|||||||
const indexed_expression_type = module.types.array.get(indexed_expression_type_index);
|
const indexed_expression_type = module.types.array.get(indexed_expression_type_index);
|
||||||
break :blk switch (indexed_expression_type.*) {
|
break :blk switch (indexed_expression_type.*) {
|
||||||
.slice => |slice| slice.element_type,
|
.slice => |slice| slice.element_type,
|
||||||
|
.array => |array| array.element_type,
|
||||||
|
.pointer => |pointer| switch (pointer.many) {
|
||||||
|
true => pointer.element_type,
|
||||||
|
false => unreachable,
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.undefined => Type.any,
|
||||||
|
.optional_unwrap => |optional_unwrap_index| blk: {
|
||||||
|
const optional_unwrap = module.values.optional_unwraps.get(optional_unwrap_index);
|
||||||
|
const optional_value = module.values.array.get(optional_unwrap.value);
|
||||||
|
const expected_optional_type_index = optional_value.getType(module);
|
||||||
|
const expected_optional_type = module.types.array.get(expected_optional_type_index);
|
||||||
|
break :blk switch (expected_optional_type.*) {
|
||||||
|
.optional => |optional| optional.element_type,
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -880,12 +978,13 @@ pub const Module = struct {
|
|||||||
blocks: BlockList(Block) = .{},
|
blocks: BlockList(Block) = .{},
|
||||||
loops: BlockList(Loop) = .{},
|
loops: BlockList(Loop) = .{},
|
||||||
assignments: BlockList(Assignment) = .{},
|
assignments: BlockList(Assignment) = .{},
|
||||||
syscalls: BlockList(Syscall) = .{},
|
intrinsics: BlockList(Intrinsic) = .{},
|
||||||
|
// syscalls: BlockList(Syscall) = .{},
|
||||||
calls: BlockList(Call) = .{},
|
calls: BlockList(Call) = .{},
|
||||||
argument_lists: BlockList(ArgumentList) = .{},
|
argument_lists: BlockList(ArgumentList) = .{},
|
||||||
returns: BlockList(Return) = .{},
|
returns: BlockList(Return) = .{},
|
||||||
container_initializations: BlockList(ContainerInitialization) = .{},
|
container_initializations: BlockList(ContainerInitialization) = .{},
|
||||||
casts: BlockList(Cast) = .{},
|
// casts: BlockList(Cast) = .{},
|
||||||
branches: BlockList(Branch) = .{},
|
branches: BlockList(Branch) = .{},
|
||||||
binary_operations: BlockList(BinaryOperation) = .{},
|
binary_operations: BlockList(BinaryOperation) = .{},
|
||||||
unary_operations: BlockList(UnaryOperation) = .{},
|
unary_operations: BlockList(UnaryOperation) = .{},
|
||||||
@ -896,13 +995,14 @@ pub const Module = struct {
|
|||||||
optional_unwraps: BlockList(OptionalUnwrap) = .{},
|
optional_unwraps: BlockList(OptionalUnwrap) = .{},
|
||||||
assembly_blocks: BlockList(Assembly.Block) = .{},
|
assembly_blocks: BlockList(Assembly.Block) = .{},
|
||||||
assembly_instructions: BlockList(Assembly.Instruction) = .{},
|
assembly_instructions: BlockList(Assembly.Instruction) = .{},
|
||||||
|
switches: BlockList(Switch) = .{},
|
||||||
} = .{},
|
} = .{},
|
||||||
types: struct {
|
types: struct {
|
||||||
array: BlockList(Type) = .{},
|
array: BlockList(Type) = .{},
|
||||||
enums: BlockList(Enum) = .{},
|
enums: BlockList(Type.Enum) = .{},
|
||||||
structs: BlockList(Struct) = .{},
|
structs: BlockList(Struct) = .{},
|
||||||
container_fields: BlockList(ContainerField) = .{},
|
container_fields: BlockList(ContainerField) = .{},
|
||||||
enum_fields: BlockList(Enum.Field) = .{},
|
enum_fields: BlockList(Type.Enum.Field) = .{},
|
||||||
function_definitions: BlockList(Function) = .{},
|
function_definitions: BlockList(Function) = .{},
|
||||||
function_declarations: BlockList(Function) = .{},
|
function_declarations: BlockList(Function) = .{},
|
||||||
function_prototypes: BlockList(Function.Prototype) = .{},
|
function_prototypes: BlockList(Function.Prototype) = .{},
|
||||||
@ -928,6 +1028,7 @@ pub const Module = struct {
|
|||||||
target: std.Target,
|
target: std.Target,
|
||||||
transpile_to_c: bool,
|
transpile_to_c: bool,
|
||||||
is_build: bool,
|
is_build: bool,
|
||||||
|
only_parse: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ImportFileResult = struct {
|
const ImportFileResult = struct {
|
||||||
@ -1144,109 +1245,132 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
|||||||
|
|
||||||
assert(module.main_package.dependencies.size == 2);
|
assert(module.main_package.dependencies.size == 2);
|
||||||
|
|
||||||
_ = try module.importPackage(compilation.base_allocator, module.main_package.dependencies.get("std").?);
|
if (!descriptor.only_parse) {
|
||||||
|
_ = try module.importPackage(compilation.base_allocator, module.main_package.dependencies.get("std").?);
|
||||||
|
} else {
|
||||||
|
_ = try module.importPackage(compilation.base_allocator, module.main_package);
|
||||||
|
}
|
||||||
|
|
||||||
for (module.map.imports.values()) |import| {
|
for (module.map.imports.values()) |import| {
|
||||||
try module.generateAbstractSyntaxTreeForFile(compilation.base_allocator, import);
|
try module.generateAbstractSyntaxTreeForFile(compilation.base_allocator, import);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline for (@typeInfo(FixedTypeKeyword).Enum.fields) |enum_field| {
|
if (!descriptor.only_parse) {
|
||||||
_ = try module.types.array.append(compilation.base_allocator, switch (@field(FixedTypeKeyword, enum_field.name)) {
|
inline for (@typeInfo(FixedTypeKeyword).Enum.fields) |enum_field| {
|
||||||
.usize => @unionInit(Type, "integer", .{
|
_ = try module.types.array.append(compilation.base_allocator, switch (@field(FixedTypeKeyword, enum_field.name)) {
|
||||||
.bit_count = 64,
|
.usize => @unionInit(Type, "integer", .{
|
||||||
.signedness = .unsigned,
|
.bit_count = 64,
|
||||||
}),
|
.signedness = .unsigned,
|
||||||
.ssize => @unionInit(Type, "integer", .{
|
}),
|
||||||
.bit_count = 64,
|
.ssize => @unionInit(Type, "integer", .{
|
||||||
.signedness = .signed,
|
.bit_count = 64,
|
||||||
}),
|
.signedness = .signed,
|
||||||
else => @unionInit(Type, enum_field.name, {}),
|
}),
|
||||||
});
|
else => @unionInit(Type, enum_field.name, {}),
|
||||||
}
|
});
|
||||||
|
}
|
||||||
inline for (@typeInfo(HardwareUnsignedIntegerType).Enum.fields) |enum_field| {
|
|
||||||
_ = try module.types.array.append(compilation.base_allocator, .{
|
inline for (@typeInfo(HardwareUnsignedIntegerType).Enum.fields) |enum_field| {
|
||||||
.integer = .{
|
_ = try module.types.array.append(compilation.base_allocator, .{
|
||||||
.signedness = .unsigned,
|
.integer = .{
|
||||||
.bit_count = switch (@field(HardwareUnsignedIntegerType, enum_field.name)) {
|
.signedness = .unsigned,
|
||||||
.u8 => 8,
|
.bit_count = switch (@field(HardwareUnsignedIntegerType, enum_field.name)) {
|
||||||
.u16 => 16,
|
.u8 => 8,
|
||||||
.u32 => 32,
|
.u16 => 16,
|
||||||
.u64 => 64,
|
.u32 => 32,
|
||||||
},
|
.u64 => 64,
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
|
}
|
||||||
inline for (@typeInfo(HardwareSignedIntegerType).Enum.fields) |enum_field| {
|
|
||||||
_ = try module.types.array.append(compilation.base_allocator, .{
|
inline for (@typeInfo(HardwareSignedIntegerType).Enum.fields) |enum_field| {
|
||||||
.integer = .{
|
_ = try module.types.array.append(compilation.base_allocator, .{
|
||||||
.signedness = .signed,
|
.integer = .{
|
||||||
.bit_count = switch (@field(HardwareSignedIntegerType, enum_field.name)) {
|
.signedness = .signed,
|
||||||
.s8 => 8,
|
.bit_count = switch (@field(HardwareSignedIntegerType, enum_field.name)) {
|
||||||
.s16 => 16,
|
.s8 => 8,
|
||||||
.s32 => 32,
|
.s16 => 16,
|
||||||
.s64 => 64,
|
.s32 => 32,
|
||||||
},
|
.s64 => 64,
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
|
}
|
||||||
for (extra_common_type_data) |type_data| {
|
|
||||||
_ = try module.types.array.append(compilation.base_allocator, type_data);
|
for (extra_common_type_data) |type_data| {
|
||||||
}
|
_ = try module.types.array.append(compilation.base_allocator, type_data);
|
||||||
semantic_analyzer.pointer_to_any_type = try module.types.array.append(compilation.base_allocator, .{
|
}
|
||||||
.pointer = .{
|
semantic_analyzer.pointer_to_any_type = try module.types.array.append(compilation.base_allocator, .{
|
||||||
.element_type = Type.any,
|
.pointer = .{
|
||||||
.many = false,
|
.element_type = Type.any,
|
||||||
.@"const" = true,
|
.many = false,
|
||||||
.termination = .none,
|
.@"const" = true,
|
||||||
},
|
.termination = .none,
|
||||||
});
|
},
|
||||||
semantic_analyzer.optional_pointer_to_any_type = try module.types.array.append(compilation.base_allocator, .{
|
});
|
||||||
.optional = .{
|
semantic_analyzer.optional_pointer_to_any_type = try module.types.array.append(compilation.base_allocator, .{
|
||||||
.element_type = semantic_analyzer.pointer_to_any_type,
|
.optional = .{
|
||||||
},
|
.element_type = semantic_analyzer.pointer_to_any_type,
|
||||||
});
|
},
|
||||||
semantic_analyzer.optional_any = try module.types.array.append(compilation.base_allocator, .{
|
});
|
||||||
.optional = .{
|
semantic_analyzer.optional_any = try module.types.array.append(compilation.base_allocator, .{
|
||||||
.element_type = Type.any,
|
.optional = .{
|
||||||
},
|
.element_type = Type.any,
|
||||||
});
|
},
|
||||||
|
});
|
||||||
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.unreachable_index = try module.values.array.append(compilation.base_allocator, .@"unreachable");
|
||||||
semantic_analyzer.optional_null_index = try module.values.array.append(compilation.base_allocator, .optional_null_literal);
|
semantic_analyzer.pointer_null_index = try module.values.array.append(compilation.base_allocator, .pointer_null_literal);
|
||||||
semantic_analyzer.undefined_index = try module.values.array.append(compilation.base_allocator, .undefined);
|
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_index = try module.values.array.append(compilation.base_allocator, .{
|
semantic_analyzer.boolean_false = try module.values.array.append(compilation.base_allocator, .{
|
||||||
.unresolved = .{
|
.bool = false,
|
||||||
.node_index = .{ .value = 0 },
|
});
|
||||||
},
|
semantic_analyzer.boolean_true = try module.values.array.append(compilation.base_allocator, .{
|
||||||
});
|
.bool = true,
|
||||||
|
});
|
||||||
try semantic_analyzer.initialize(compilation, module, packages[0], value_index);
|
|
||||||
|
const value_index = try module.values.array.append(compilation.base_allocator, .{
|
||||||
if (descriptor.transpile_to_c) {
|
.unresolved = .{
|
||||||
try c_transpiler.initialize(compilation, module, descriptor);
|
.node_index = .{ .value = 0 },
|
||||||
if (descriptor.is_build) {
|
},
|
||||||
var process = std.ChildProcess.init(&.{descriptor.executable_path}, compilation.base_allocator);
|
});
|
||||||
switch (try process.spawnAndWait()) {
|
|
||||||
.Exited => |exit_code| {
|
try semantic_analyzer.initialize(compilation, module, packages[0], value_index);
|
||||||
if (exit_code != 0) {
|
|
||||||
@panic("Exited with errors");
|
if (descriptor.transpile_to_c) {
|
||||||
}
|
try c_transpiler.initialize(compilation, module, descriptor);
|
||||||
},
|
if (descriptor.is_build) {
|
||||||
else => @panic("Unexpected program state"),
|
const argv = [_][]const u8{ descriptor.executable_path, "--compiler", compilation.executable_absolute_path };
|
||||||
}
|
const process_result = try std.ChildProcess.run(.{
|
||||||
|
.allocator = compilation.base_allocator,
|
||||||
|
.argv = &argv,
|
||||||
|
});
|
||||||
|
|
||||||
|
switch (process_result.term) {
|
||||||
|
.Exited => |exit_code| {
|
||||||
|
if (exit_code != 0) {
|
||||||
|
for (argv) |arg| {
|
||||||
|
std.debug.print("{s} ", .{arg});
|
||||||
|
}
|
||||||
|
std.debug.print("exited with failure: {}\n", .{exit_code});
|
||||||
|
std.debug.print("STDOUT:\n```\n{s}\n```\n", .{process_result.stdout});
|
||||||
|
std.debug.print("STDERR:\n```\n{s}\n```\n", .{process_result.stderr});
|
||||||
|
@panic("Internal error");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => @panic("Unexpected program state"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable;
|
||||||
|
// const ir = try intermediate_representation.initialize(compilation, module);
|
||||||
|
//
|
||||||
|
// switch (descriptor.target.cpu.arch) {
|
||||||
|
// inline else => |arch| try emit.get(arch).initialize(compilation.base_allocator, ir, descriptor),
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unreachable;
|
|
||||||
// const ir = try intermediate_representation.initialize(compilation, module);
|
|
||||||
//
|
|
||||||
// switch (descriptor.target.cpu.arch) {
|
|
||||||
// inline else => |arch| try emit.get(arch).initialize(compilation.base_allocator, ir, descriptor),
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1317,6 +1441,10 @@ pub const File = struct {
|
|||||||
fn parse(file: *File, allocator: Allocator, file_index: File.Index) !void {
|
fn parse(file: *File, allocator: Allocator, file_index: File.Index) !void {
|
||||||
assert(file.status == .lexed);
|
assert(file.status == .lexed);
|
||||||
file.syntactic_analyzer_result = try syntactic_analyzer.analyze(allocator, file.lexical_analyzer_result.tokens.items, file.source_code, file_index);
|
file.syntactic_analyzer_result = try syntactic_analyzer.analyze(allocator, file.lexical_analyzer_result.tokens.items, file.source_code, file_index);
|
||||||
|
|
||||||
|
// if (file_index.uniqueInteger() == 5) {
|
||||||
|
// assert(file.syntactic_analyzer_result.nodes.items[1356].id != .node_list);
|
||||||
|
// }
|
||||||
// if (!@import("builtin").is_test) {
|
// if (!@import("builtin").is_test) {
|
||||||
// print("[SYNTACTIC ANALYSIS] {} ns\n", .{file.syntactic_analyzer_result.time});
|
// print("[SYNTACTIC ANALYSIS] {} ns\n", .{file.syntactic_analyzer_result.time});
|
||||||
// }
|
// }
|
||||||
@ -1353,7 +1481,7 @@ fn getLoggerScopeType(comptime logger_scope: LoggerScope) type {
|
|||||||
|
|
||||||
var logger_bitset = std.EnumSet(LoggerScope).initEmpty();
|
var logger_bitset = std.EnumSet(LoggerScope).initEmpty();
|
||||||
|
|
||||||
var writer = std.io.getStdErr().writer();
|
var writer = std.io.getStdOut().writer();
|
||||||
|
|
||||||
fn shouldLog(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger_scope).Logger) bool {
|
fn shouldLog(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger_scope).Logger) bool {
|
||||||
return logger_bitset.contains(logger_scope) and getLoggerScopeType(logger_scope).Logger.bitset.contains(logger);
|
return logger_bitset.contains(logger_scope) and getLoggerScopeType(logger_scope).Logger.bitset.contains(logger);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,7 @@ pub fn BlockList(comptime T: type) type {
|
|||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
// TODO: make this not reallocate the whole block. Instead, use a pointer to the block as the ArrayList item
|
// TODO: make this not reallocate the whole block. Instead, use a pointer to the block as the ArrayList item
|
||||||
blocks: ArrayList(Block) = .{},
|
blocks: ArrayList(*Block) = .{},
|
||||||
len: usize = 0,
|
len: usize = 0,
|
||||||
first_block: u32 = 0,
|
first_block: u32 = 0,
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ pub fn BlockList(comptime T: type) type {
|
|||||||
const max_allocation = list.blocks.items.len * item_count;
|
const max_allocation = list.blocks.items.len * item_count;
|
||||||
const result = switch (list.len < max_allocation) {
|
const result = switch (list.len < max_allocation) {
|
||||||
true => blk: {
|
true => blk: {
|
||||||
const block = &list.blocks.items[list.first_block];
|
const block = list.blocks.items[list.first_block];
|
||||||
if (block.allocateIndex()) |element_index| {
|
if (block.allocateIndex()) |element_index| {
|
||||||
break :blk Index{
|
break :blk Index{
|
||||||
.element = element_index,
|
.element = element_index,
|
||||||
@ -148,13 +148,11 @@ pub fn BlockList(comptime T: type) type {
|
|||||||
},
|
},
|
||||||
false => blk: {
|
false => blk: {
|
||||||
const block_index = list.blocks.items.len;
|
const block_index = list.blocks.items.len;
|
||||||
const new_block = list.blocks.addOneAssumeCapacity();
|
const new_block = try allocator.create(Block);
|
||||||
new_block.* = .{};
|
new_block.* = .{};
|
||||||
|
list.blocks.appendAssumeCapacity(new_block);
|
||||||
const element_index = new_block.allocateIndex() catch unreachable;
|
const element_index = new_block.allocateIndex() catch unreachable;
|
||||||
const ptr = &new_block.items[element_index];
|
|
||||||
_ = ptr;
|
|
||||||
list.first_block += @intFromBool(block_index != 0);
|
list.first_block += @intFromBool(block_index != 0);
|
||||||
|
|
||||||
break :blk Index{
|
break :blk Index{
|
||||||
.element = element_index,
|
.element = element_index,
|
||||||
.block = @intCast(block_index),
|
.block = @intCast(block_index),
|
||||||
|
@ -14,7 +14,8 @@ const File = Compilation.File;
|
|||||||
const logln = Compilation.logln;
|
const logln = Compilation.logln;
|
||||||
const fs = @import("../fs.zig");
|
const fs = @import("../fs.zig");
|
||||||
|
|
||||||
pub const Token = packed struct(u64) {
|
// TODO: switch to packed struct when speed is important
|
||||||
|
pub const Token = struct {
|
||||||
start: u32,
|
start: u32,
|
||||||
len: u24,
|
len: u24,
|
||||||
id: Id,
|
id: Id,
|
||||||
@ -85,6 +86,7 @@ pub const Token = packed struct(u64) {
|
|||||||
fixed_keyword_cc = 0x98,
|
fixed_keyword_cc = 0x98,
|
||||||
fixed_keyword_for = 0x99,
|
fixed_keyword_for = 0x99,
|
||||||
fixed_keyword_undefined = 0x9a,
|
fixed_keyword_undefined = 0x9a,
|
||||||
|
fixed_keyword_break = 0x9b,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Index = u32;
|
pub const Index = u32;
|
||||||
@ -119,6 +121,7 @@ pub const FixedKeyword = enum {
|
|||||||
cc,
|
cc,
|
||||||
@"for",
|
@"for",
|
||||||
undefined,
|
undefined,
|
||||||
|
@"break",
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Result = struct {
|
pub const Result = struct {
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3
ci.sh
3
ci.sh
@ -54,7 +54,6 @@ echo -e "\e[35m[SUMMARY]\e[0m"
|
|||||||
echo -e "\e[35m=========\e[0m"
|
echo -e "\e[35m=========\e[0m"
|
||||||
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 $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)."
|
echo -e "Ran $ran_test_count tests (\e[32m $passed_test_count\e[0m passed, \e[31m$failed_test_count\e[0m failed)."
|
||||||
echo -e "\e[35m=========\e[0m"
|
|
||||||
|
|
||||||
if [[ "$failed_compilation_count" != "0" ]]; then
|
if [[ "$failed_compilation_count" != "0" ]]; then
|
||||||
printf $"\nFailed compilations:\n"
|
printf $"\nFailed compilations:\n"
|
||||||
@ -74,6 +73,8 @@ if [[ "$failed_test_count" != "0" ]]; then
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo -e "\e[35m=========\e[0m"
|
||||||
|
|
||||||
if [[ "$failed_test_count" == "0" && "$failed_compilation_count" == "0" ]]; then
|
if [[ "$failed_test_count" == "0" && "$failed_compilation_count" == "0" ]]; then
|
||||||
echo -e "\e[32mSUCCESS!\e[0m"
|
echo -e "\e[32mSUCCESS!\e[0m"
|
||||||
true
|
true
|
||||||
|
@ -1,7 +1,47 @@
|
|||||||
const std = #import("std");
|
const std = #import("std");
|
||||||
|
const assert = std.assert;
|
||||||
|
const Allocator = std.Allocator;
|
||||||
const Target = std.Target;
|
const Target = std.Target;
|
||||||
|
|
||||||
const Executable = struct{
|
const Executable = struct{
|
||||||
target: Target,
|
target: Target,
|
||||||
main_source_path: []const u8,
|
main_source_path: [:0]const u8,
|
||||||
|
|
||||||
|
const compile = fn(executable: Executable, compiler_path: [&:0]const u8) bool {
|
||||||
|
if (std.os.duplicate_process()) |pid| {
|
||||||
|
if (pid == 0) {
|
||||||
|
const argv = [_:null] ?[&:0]const u8{ compiler_path, #cast(executable.main_source_path.ptr), };
|
||||||
|
std.os.execute(path = compiler_path, argv = argv.&, env = std.start.environment_values);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (std.os.waitpid(pid, flags = 0)) |raw_status| {
|
||||||
|
if (std.os.ifexited(status = raw_status)) {
|
||||||
|
const exit_status = std.os.exitstatus(status = raw_status);
|
||||||
|
|
||||||
|
if (exit_status == 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
std.print(bytes = "Bad exit code\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (std.os.ifsignaled(status = raw_status)) {
|
||||||
|
std.print(bytes = "Signaled\n");
|
||||||
|
return false;
|
||||||
|
} else if (std.os.ifstopped(status = raw_status)) {
|
||||||
|
std.print(bytes = "Stopped\n");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
std.print(bytes = "Unknown process termination\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std.print(bytes = "Wait failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std.print(bytes = "Unable to create child process\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
284
lib/std/os.nat
284
lib/std/os.nat
@ -7,10 +7,9 @@ const system = switch (current) {
|
|||||||
.windows => windows,
|
.windows => windows,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const exit = fn(exit_code: s32) noreturn {
|
const exit = fn(exit_code: s32) noreturn {
|
||||||
switch (current) {
|
switch (current) {
|
||||||
.linux => _ = #syscall(231, exit_code),
|
.linux => _ = #syscall(#cast(linux.Syscall.exit_group), exit_code),
|
||||||
.macos => macos.exit(exit_code),
|
.macos => macos.exit(exit_code),
|
||||||
.windows => windows.ExitProcess(exit_code),
|
.windows => windows.ExitProcess(exit_code),
|
||||||
}
|
}
|
||||||
@ -18,7 +17,64 @@ const exit = fn(exit_code: s32) noreturn {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProcessId = system.ProcessId;
|
const max_file_operation_byte_count = switch (current) {
|
||||||
|
.linux => 0x7ffff000,
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const FileDescriptor = struct{
|
||||||
|
handle: system.FileDescriptor,
|
||||||
|
|
||||||
|
const read = fn(file_descriptor: FileDescriptor, bytes: []u8) ?usize {
|
||||||
|
if (bytes.len > 0) {
|
||||||
|
switch (current) {
|
||||||
|
.linux => {
|
||||||
|
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||||
|
if (linux.unwrapSyscall(syscall_result = #syscall(#cast(linux.Syscall.read), file_descriptor.handle, #cast(bytes.ptr), len))) |byte_count| {
|
||||||
|
return byte_count;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const write = fn (file_descriptor: FileDescriptor, bytes: []const u8) ?usize {
|
||||||
|
switch (current) {
|
||||||
|
.linux => {
|
||||||
|
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||||
|
const raw_result = #syscall(#cast(linux.Syscall.write), file_descriptor.handle, #cast(bytes.ptr), len);
|
||||||
|
if (linux.unwrapSyscall(syscall_result = raw_result)) |byte_count| {
|
||||||
|
return byte_count;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const StdFileDescriptor = enum {
|
||||||
|
stdin = 0,
|
||||||
|
stdout = 1,
|
||||||
|
stderr = 2,
|
||||||
|
|
||||||
|
const get = fn(descriptor: StdFileDescriptor) FileDescriptor{
|
||||||
|
switch (current) {
|
||||||
|
.linux, .macos => {
|
||||||
|
return FileDescriptor{
|
||||||
|
.handle = #cast(descriptor),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const ProtectionFlags = struct(u32){
|
const ProtectionFlags = struct(u32){
|
||||||
read: bool,
|
read: bool,
|
||||||
@ -83,16 +139,11 @@ const max_path_byte_count = switch (current) {
|
|||||||
else => #error("OS not supported"),
|
else => #error("OS not supported"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const current_executable_path = fn(allocator: &Allocator) ?[]u8 {
|
const current_executable_path = fn(buffer: []u8) ?[]u8 {
|
||||||
switch (current) {
|
switch (current) {
|
||||||
.linux => {
|
.linux => {
|
||||||
var buffer: [max_path_byte_count]u8 = undefined;
|
if (readlink(file_path = "/proc/self/exe", buffer)) |bytes| {
|
||||||
if (readlink(file_path = "/proc/self/exe", buffer = buffer.&)) |bytes| {
|
return bytes;
|
||||||
if (allocator.duplicate_bytes(bytes)) |result| {
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -101,7 +152,11 @@ const current_executable_path = fn(allocator: &Allocator) ?[]u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const duplicate_process = fn () ?ProcessId {
|
const Process = struct{
|
||||||
|
const Id = system.ProcessId;
|
||||||
|
};
|
||||||
|
|
||||||
|
const duplicate_process = fn () ?Process.Id {
|
||||||
switch (current) {
|
switch (current) {
|
||||||
.linux => {
|
.linux => {
|
||||||
if (linux.unwrapSyscall(syscall_result = linux.fork())) |fork_result| {
|
if (linux.unwrapSyscall(syscall_result = linux.fork())) |fork_result| {
|
||||||
@ -123,41 +178,186 @@ const execute = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileDescriptor = struct{
|
const event_file_descriptor = fn(initial_value: u32, flags: u32) ?s32 {
|
||||||
handle: system.FileDescriptor,
|
switch (current) {
|
||||||
|
.linux => {
|
||||||
const write = fn (file_descriptor: FileDescriptor, bytes: []const u8) ?usize {
|
if (linux.unwrapSyscall(syscall_result = linux.event_file_descriptor(count = initial_value, flags))) |raw_result| {
|
||||||
switch (current) {
|
const result: s32 = #cast(raw_result);
|
||||||
.linux => {
|
return result;
|
||||||
const raw_result = #syscall(1, file_descriptor.handle, #cast(bytes.ptr), bytes.len);
|
} else {
|
||||||
if (linux.unwrapSyscall(syscall_result = raw_result)) |byte_count| {
|
return null;
|
||||||
return byte_count;
|
}
|
||||||
} else {
|
},
|
||||||
return null;
|
else => #error("OS not supported"),
|
||||||
}
|
|
||||||
},
|
|
||||||
else => #error("OS not supported"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const StdFileDescriptor = enum {
|
const dup2 = fn(old_file_descriptor: system.FileDescriptor, new_file_descriptor: system.FileDescriptor) bool {
|
||||||
stdin = 0,
|
switch (current) {
|
||||||
stdout = 1,
|
.linux => {
|
||||||
stderr = 2,
|
if (linux.unwrapSyscall(syscall_result = linux.dup2(old = old_file_descriptor, new = new_file_descriptor))) |_| {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const get = fn(descriptor: StdFileDescriptor) FileDescriptor{
|
const open = fn(path: [&:0]const u8, flags: u32, permissions: u32) ?FileDescriptor{
|
||||||
switch (current) {
|
switch (current) {
|
||||||
.linux, .macos => {
|
.linux => {
|
||||||
return FileDescriptor{
|
if (linux.unwrapSyscall(syscall_result = linux.open(path, flags, permissions))) |raw_result| {
|
||||||
.handle = #cast(descriptor),
|
const file_descriptor = FileDescriptor{
|
||||||
|
.handle = #cast(raw_result),
|
||||||
};
|
};
|
||||||
},
|
|
||||||
else => #error("OS not supported"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
return file_descriptor;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const close = fn(file_descriptor: s32) bool {
|
||||||
|
switch (current) {
|
||||||
|
.linux => {
|
||||||
|
if (linux.unwrapSyscall(syscall_result = linux.close(file_descriptor))) |_| {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pipe2 = fn(flags: u32) ?[2]system.FileDescriptor{
|
||||||
|
switch (current) {
|
||||||
|
.linux => {
|
||||||
|
var pipe: [2]s32 = undefined;
|
||||||
|
if (linux.unwrapSyscall(syscall_result = linux.pipe2(pipe_pointer = pipe.&, flags))) |_| {
|
||||||
|
return pipe;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const set_up_child_process_io_posix = fn(io_channel_behavior: IoChannelBehavior, pipe_file_descriptor: s32, std_io_channel_descriptor: s32, dev_null_file_descriptor: s32) bool {
|
||||||
|
switch (io_channel_behavior) {
|
||||||
|
.pipe => return dup2(old_file_descriptor = pipe_file_descriptor, new_file_descriptor = std_io_channel_descriptor),
|
||||||
|
.close => {
|
||||||
|
if (!close(file_descriptor = std_io_channel_descriptor)) {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
.inherit => return true,
|
||||||
|
.ignore => return dup2(old_file_descriptor = dev_null_file_descriptor, new_file_descriptor = std_io_channel_descriptor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PollFileDescriptor = system.PollFileDescriptor;
|
||||||
|
|
||||||
|
const poll = fn(file_descriptors: []PollFileDescriptor, timeout: s32) ?usize {
|
||||||
|
switch (current) {
|
||||||
|
.linux => {
|
||||||
|
if (linux.unwrapSyscall(syscall_result = linux.poll(file_descriptors = file_descriptors.ptr, file_descriptor_count = file_descriptors.len, timeout = timeout))) |result| {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const write_u64_pipe = fn (file_handle: s32, value: u64) ?usize {
|
||||||
|
const file = FileDescriptor{
|
||||||
|
.handle = file_handle,
|
||||||
|
};
|
||||||
|
const value_ptr: [&]u8 = #cast(value.&);
|
||||||
|
const bytes = value_ptr[0..#size(u64)];
|
||||||
|
return file.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
const read_u64_pipe = fn (file_handle: s32) ?u64{
|
||||||
|
const file = FileDescriptor{
|
||||||
|
.handle = file_handle,
|
||||||
|
};
|
||||||
|
var value: u64 = 0;
|
||||||
|
const value_ptr: [&]u8 = #cast(value.&);
|
||||||
|
const bytes = value_ptr[0..#size(u64)];
|
||||||
|
if (file.read(bytes)) |character_read_count| {
|
||||||
|
if (character_read_count == #size(u64)) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const termsig = fn(status: u32) u32 {
|
||||||
|
return status & 0x7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ifexited = fn(status: u32) bool {
|
||||||
|
return termsig(status) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const exitstatus = fn(status: u32) u8 {
|
||||||
|
const result: u8 = #cast((status & 0xff00) >> 8);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopsig = fn(status: u32) u32 {
|
||||||
|
return exitstatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ifstopped = fn(status: u32) bool {
|
||||||
|
const result: u16 = #cast(((status & 0xffff) * 0x10001) >> 8);
|
||||||
|
return result > 0x7f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ifsignaled = fn(status: u32) bool {
|
||||||
|
return (status & 0xffff) - 1 < 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
const waitpid = fn(pid: Process.Id, flags: u32) ?u32 {
|
||||||
|
switch (current) {
|
||||||
|
.linux => {
|
||||||
|
var status: u32 = undefined;
|
||||||
|
while (true) {
|
||||||
|
const raw_syscall_result = linux.waitpid(pid, status = status.&, flags, resource_usage = 0);
|
||||||
|
const signed_syscall_result: ssize = #cast(raw_syscall_result);
|
||||||
|
if (raw_syscall_result != -4) {
|
||||||
|
if (linux.unwrapSyscall(syscall_result = raw_syscall_result)) |_| {
|
||||||
|
return status;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => #error("OS not supported"),
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const IoChannelBehavior = enum{
|
||||||
|
pipe,
|
||||||
|
close,
|
||||||
|
inherit,
|
||||||
|
ignore,
|
||||||
|
};
|
||||||
|
|
||||||
const linux = #import("os/linux.nat");
|
const linux = #import("os/linux.nat");
|
||||||
const macos = #import("os/macos.nat");
|
const macos = #import("os/macos.nat");
|
||||||
|
@ -435,6 +435,56 @@ const execve = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const event_file_descriptor = fn(count: u32, flags: u32) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.eventfd2), #cast(count), #cast(flags));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dup2 = fn(old: s32, new: s32) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.dup2), #cast(old), #cast(new));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = fn(path: [&:0]const u8, flags: u32, permissions: u32) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.open), #cast(path), flags, permissions);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const openat = fn(directory_file_descriptor: s32, path: [&:0]const u8, flags: u32, permissions: u32) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.openat), #cast(directory_file_descriptor), #cast(path), flags, permissions);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const read = fn(file_descriptor: s32, bytes_ptr: [&]u8, bytes_len: usize) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.read), #cast(file_descriptor), #cast(bytes_ptr), bytes_len);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const write = fn(file_descriptor: s32, bytes_ptr: [&]const u8, bytes_len: usize) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.write), #cast(file_descriptor), #cast(bytes_ptr), bytes_len);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const close = fn(file_descriptor: s32) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.close), #cast(file_descriptor));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pipe2 = fn (pipe_pointer: &[2]s32, flags: u32) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.pipe2), #cast(pipe_pointer), flags);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const waitpid = fn(pid: ProcessId, status: &u32, flags: u32, resource_usage: usize) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.wait4), pid, #cast(status), flags, resource_usage);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const poll = fn(file_descriptors: [&]PollFileDescriptor, file_descriptor_count: usize, timeout: s32) usize {
|
||||||
|
const result = #syscall(#cast(Syscall.poll), #cast(file_descriptors), file_descriptor_count, #cast(timeout));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
const unwrapSyscall = fn(syscall_result: usize) ?usize {
|
const unwrapSyscall = fn(syscall_result: usize) ?usize {
|
||||||
const signed_syscall_result: ssize = #cast(syscall_result);
|
const signed_syscall_result: ssize = #cast(syscall_result);
|
||||||
if (signed_syscall_result >= 0) {
|
if (signed_syscall_result >= 0) {
|
||||||
@ -443,3 +493,26 @@ const unwrapSyscall = fn(syscall_result: usize) ?usize {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EventFileDescriptorFlags = enum(u32) {
|
||||||
|
semaphore = 1,
|
||||||
|
cloexec = 0o2000000,
|
||||||
|
nonblock = 0o4000,
|
||||||
|
};
|
||||||
|
|
||||||
|
const PollFileDescriptor = struct{
|
||||||
|
file_descriptor: FileDescriptor,
|
||||||
|
events: Poll,
|
||||||
|
revents: Poll,
|
||||||
|
|
||||||
|
const Poll = struct(u16) {
|
||||||
|
in: bool = false,
|
||||||
|
pri: bool = false,
|
||||||
|
out: bool = false,
|
||||||
|
err: bool = false,
|
||||||
|
hup: bool = false,
|
||||||
|
nval: bool = false,
|
||||||
|
rdnorm: bool = false,
|
||||||
|
rdband: bool = false,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -6,12 +6,24 @@ comptime {
|
|||||||
const _start = fn () noreturn export cc(.naked) {
|
const _start = fn () noreturn export cc(.naked) {
|
||||||
#asm({
|
#asm({
|
||||||
xor ebp, ebp;
|
xor ebp, ebp;
|
||||||
|
mov rdi, rsp;
|
||||||
and rsp, 0xfffffffffffffff0;
|
and rsp, 0xfffffffffffffff0;
|
||||||
call {start};
|
call {start};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = fn() noreturn export {
|
var argument_count: usize = 0;
|
||||||
|
var argument_values: [&]const [&:0]const u8 = undefined;
|
||||||
|
var environment_values: [&:null]const ?[&:null]const u8 = undefined;
|
||||||
|
|
||||||
|
const start = fn(argc_argv_address: usize) noreturn export {
|
||||||
|
var argument_address_iterator = argc_argv_address;
|
||||||
|
const argument_count_ptr: &usize = #cast(argument_address_iterator);
|
||||||
|
argument_count = argument_count_ptr.@;
|
||||||
|
argument_address_iterator += #size(usize);
|
||||||
|
argument_values = #cast(argument_address_iterator);
|
||||||
|
argument_address_iterator += #size(usize) * (argument_count + 1);
|
||||||
|
environment_values = #cast(argument_address_iterator);
|
||||||
const result = #import("main").main();
|
const result = #import("main").main();
|
||||||
std.os.exit(exit_code = result);
|
std.os.exit(exit_code = result);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const main = fn () s32 {
|
const main = fn() s32 {
|
||||||
const dividend: s32 = 30;
|
const dividend: s32 = 30;
|
||||||
const divisor: s32 = 6;
|
const divisor: s32 = 6;
|
||||||
const div: s32 = dividend / divisor;
|
const div: s32 = dividend / divisor;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const main = fn () s32 {
|
const main = fn() s32 {
|
||||||
var counter: s32 = 0;
|
var counter: s32 = 0;
|
||||||
const loop = 10;
|
const loop = 10;
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const std = #import("std");
|
const std = #import("std");
|
||||||
|
|
||||||
const main = fn() s32 {
|
const main = fn() s32 {
|
||||||
if (std.os.duplicate_process()) |pid| {
|
if (std.os.duplicate_process()) |pid| {
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
const std = #import("std");
|
const std = #import("std");
|
||||||
const main = fn() s32{
|
|
||||||
|
const main = fn() s32 {
|
||||||
if (std.os.duplicate_process()) |pid| {
|
if (std.os.duplicate_process()) |pid| {
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
std.print(bytes = "Hello from child\n");
|
std.print(bytes = "Hello from child\n");
|
||||||
const argv = [_:null] ?[&:0]const u8{"/usr/bin/ls"};
|
const argv = [_:null] ?[&:0]const u8{"/usr/bin/ls"};
|
||||||
const env = [_:null] ?[&:null]const u8 {};
|
std.os.execute(path = "/usr/bin/ls", argv = argv.&, env = std.start.environment_values);
|
||||||
std.os.execute(path = "/usr/bin/ls", argv = argv.&, env = env.&);
|
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
std.print(bytes = "Hello from parent\n");
|
std.print(bytes = "Hello from parent\n");
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const main = fn () s32 {
|
const main = fn() s32 {
|
||||||
const a: s32 = 5;
|
const a: s32 = 5;
|
||||||
const b: s32 = 4;
|
const b: s32 = 4;
|
||||||
return a * b - a * b;
|
return a * b - a * b;
|
||||||
|
11
test/loop_break/main.nat
Normal file
11
test/loop_break/main.nat
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const main = fn() s32 {
|
||||||
|
var i: s32 = 0;
|
||||||
|
while (i < 10) {
|
||||||
|
i += 1;
|
||||||
|
if (i == 5) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i - 5;
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
const std = #import("std");
|
const std = #import("std");
|
||||||
const print = std.print;
|
const print = std.print;
|
||||||
|
|
||||||
const main = fn () s32 {
|
const main = fn() s32 {
|
||||||
if (std.os.current_executable_path(allocator = std.page_allocator.allocator.&)) |bytes| {
|
var buffer: [std.os.max_path_byte_count + 1]u8 = undefined;
|
||||||
|
if (std.os.current_executable_path(buffer = buffer.&)) |bytes| {
|
||||||
print(bytes);
|
print(bytes);
|
||||||
print(bytes = "\n");
|
print(bytes = "\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const main = fn () s32 {
|
const main = fn() s32 {
|
||||||
var false_boolean: bool = false;
|
var false_boolean: bool = false;
|
||||||
if (false_boolean) {
|
if (false_boolean) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2,6 +2,7 @@ const std = #import("std");
|
|||||||
|
|
||||||
const main = fn() s32 {
|
const main = fn() s32 {
|
||||||
const size = 0x1000;
|
const size = 0x1000;
|
||||||
|
|
||||||
if (std.page_allocator.allocate(size, alignment = 12)) |result| {
|
if (std.page_allocator.allocate(size, alignment = 12)) |result| {
|
||||||
result[0] = 0;
|
result[0] = 0;
|
||||||
std.print(bytes = "Allocation succeeded. Freeing...\n");
|
std.print(bytes = "Allocation succeeded. Freeing...\n");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user