diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index 3aa88d5..f4c7dce 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -1360,7 +1360,7 @@ pub fn log(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger } pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, return_address: ?usize) noreturn { - const print_stack_trace = false; + const print_stack_trace = true; switch (print_stack_trace) { true => @call(.always_inline, std.builtin.default_panic, .{ message, stack_trace, return_address }), false => { diff --git a/bootstrap/backend/c_transpiler.zig b/bootstrap/backend/c_transpiler.zig index 7371899..518a952 100644 --- a/bootstrap/backend/c_transpiler.zig +++ b/bootstrap/backend/c_transpiler.zig @@ -38,7 +38,7 @@ pub const TranslationUnit = struct { enum_type_set: AutoArrayHashMap(Compilation.Type.Index, []const u8) = .{}, declaration_set: AutoArrayHashMap(Compilation.Declaration.Index, []const u8) = .{}, - const SyscallBitset = std.StaticBitSet(6); + const SyscallBitset = std.StaticBitSet(7); fn create(module: *Module, allocator: Allocator) !*TranslationUnit { var unit = try allocator.create(TranslationUnit); @@ -645,12 +645,14 @@ pub const TranslationUnit = struct { try list.append(allocator, '_'); try list.appendSlice(allocator, enum_field_name); - try list.appendSlice(allocator, " = "); + if (!enum_field.value.invalid) { + try list.appendSlice(allocator, " = "); - try unit.writeValue(module, &list, allocator, Compilation.Type.Index.invalid, 0, .{ - .value_index = enum_field.value, - .type_index = Compilation.Type.usize, - }); + try unit.writeValue(module, &list, allocator, Compilation.Type.Index.invalid, 0, .{ + .value_index = enum_field.value, + .type_index = Compilation.Type.usize, + }); + } try list.appendSlice(allocator, ",\n"); } @@ -795,7 +797,7 @@ pub const TranslationUnit = struct { const syscall = module.values.syscalls.get(syscall_index); const arguments = syscall.getArguments(); - if (!unit.syscall_bitset.isSet(arguments.len - 1)) { + if (!unit.syscall_bitset.isSet(arguments.len)) { try unit.function_declarations.appendSlice(allocator, "static __inline u64 syscall"); try unit.function_declarations.writer(allocator).print("{}(", .{arguments.len}); try unit.function_declarations.appendSlice(allocator, "u64 n, "); @@ -849,7 +851,7 @@ pub const TranslationUnit = struct { \\ ); - unit.syscall_bitset.set(arguments.len - 1); + unit.syscall_bitset.set(arguments.len); } try list.writer(allocator).print("syscall{}(", .{arguments.len}); diff --git a/bootstrap/frontend/semantic_analyzer.zig b/bootstrap/frontend/semantic_analyzer.zig index 40854ec..072c670 100644 --- a/bootstrap/frontend/semantic_analyzer.zig +++ b/bootstrap/frontend/semantic_analyzer.zig @@ -2631,6 +2631,7 @@ const Analyzer = struct { break :blk switch (backing_type_token.id) { .keyword_unsigned_integer => if (equal(u8, token_bytes, "u8")) Type.u8 else if (equal(u8, token_bytes, "u16")) Type.u16 else if (equal(u8, token_bytes, "u32")) Type.u32 else if (equal(u8, token_bytes, "u64")) Type.u64 else if (equal(u8, token_bytes, "usize")) Type.usize else unreachable, + .fixed_keyword_usize => Type.usize, else => |t| @panic(@tagName(t)), }; } @@ -2988,11 +2989,26 @@ const Analyzer = struct { const backing_integer_type = analyzer.module.types.array.get(struct_type.backing_type); if (backing_integer_type.integer.bit_count >> 3 <= flexible_integer.byte_count) { return .success; + } else { + unreachable; } } unreachable; }, + .@"enum" => |enum_index| { + const enum_type = analyzer.module.types.enums.get(enum_index); + if (!enum_type.backing_type.invalid) { + const backing_integer_type = analyzer.module.types.array.get(enum_type.backing_type); + if (backing_integer_type.integer.bit_count >> 3 <= flexible_integer.byte_count) { + return .success; + } else { + unreachable; + } + } else { + unreachable; + } + }, else => |t| @panic(@tagName(t)), }; }, @@ -3007,6 +3023,7 @@ const Analyzer = struct { .integer => |integer| switch (destination_type.*) { .optional => |optional| switch (analyzer.module.types.array.get(optional.element_type).*) { .pointer => if (integer.bit_count == 64) .success else unreachable, + .integer => .cast_to_optional, else => |t| @panic(@tagName(t)), }, .integer => .success, @@ -3478,30 +3495,33 @@ const Analyzer = struct { assert(expect_type != .none); const cast_result = try analyzer.canCast(expect_type, value_type); - if (cast_result == .success) { - const cast_index = try analyzer.module.values.casts.append(analyzer.allocator, .{ - .value = value_to_cast_index, - .type = switch (expect_type) { - .none => unreachable, - .flexible_integer => |flexible_integer| if (flexible_integer.sign) |sign| switch (sign) { - else => unreachable, - } else switch (flexible_integer.byte_count) { - 1 => Type.u8, - 2 => Type.u16, - 4 => Type.u32, - 8 => Type.u64, + switch (cast_result) { + inline .success, .cast_to_optional => |cast_type| { + const cast_index = try analyzer.module.values.casts.append(analyzer.allocator, .{ + .value = value_to_cast_index, + .type = switch (expect_type) { + .none => unreachable, + .flexible_integer => |flexible_integer| if (flexible_integer.sign) |sign| switch (sign) { + else => unreachable, + } else switch (flexible_integer.byte_count) { + 1 => Type.u8, + 2 => Type.u16, + 4 => Type.u32, + 8 => Type.u64, + else => unreachable, + }, + .type_index => |type_index| type_index, else => unreachable, }, - .type_index => |type_index| type_index, - else => unreachable, - }, - }); + }); - break :blk Value{ - .cast = cast_index, - }; - } else { - std.debug.panic("Can't cast", .{}); + break :blk @unionInit(Value, switch (cast_type) { + .success => "cast", + .cast_to_optional => "optional_cast", + else => @compileError("WTF"), + }, cast_index); + }, + else => @panic("can't cast"), } }, }; diff --git a/bootstrap/frontend/syntactic_analyzer.zig b/bootstrap/frontend/syntactic_analyzer.zig index f7884f7..edce878 100644 --- a/bootstrap/frontend/syntactic_analyzer.zig +++ b/bootstrap/frontend/syntactic_analyzer.zig @@ -1565,6 +1565,13 @@ const Analyzer = struct { .fixed_keyword_enum => blk: { analyzer.token_i += 1; + // TODO: is this the best way? + if (analyzer.tokens[analyzer.token_i].id == .left_parenthesis) { + analyzer.token_i += 1; + assert(analyzer.tokens[analyzer.token_i + 1].id == .right_parenthesis); + analyzer.token_i += 2; + } + _ = try analyzer.expectToken(.left_brace); const node_list = try analyzer.containerMembers(.@"enum"); _ = try analyzer.expectToken(.right_brace); diff --git a/lib/std/build.nat b/lib/std/build.nat new file mode 100644 index 0000000..cd25921 --- /dev/null +++ b/lib/std/build.nat @@ -0,0 +1,7 @@ +const std = #import("std"); +const Target = std.Target; + +const Executable = struct{ + target: Target, + main_source_path: []const u8, +}; diff --git a/lib/std/builtin.nat b/lib/std/builtin.nat index 7c41626..924d084 100644 --- a/lib/std/builtin.nat +++ b/lib/std/builtin.nat @@ -2,10 +2,10 @@ const Os = enum{ linux, macos, windows, + freestanding, }; const Cpu = enum{ - aarch64, x86_64, }; diff --git a/lib/std/os.nat b/lib/std/os.nat index 014c85b..3ec2a96 100644 --- a/lib/std/os.nat +++ b/lib/std/os.nat @@ -18,6 +18,8 @@ const exit = fn(exit_code: s32) noreturn { unreachable; } +const ProcessId = system.ProcessId; + const ProtectionFlags = struct(u32){ read: bool, write: bool, @@ -99,6 +101,19 @@ const current_executable_path = fn(allocator: &Allocator) ?[]u8 { } } +const duplicate_process = fn () ?ProcessId { + switch (current) { + .linux => { + if (linux.unwrapSyscall(syscall_result = linux.fork())) |fork_result| { + return #cast(fork_result); + } else { + return null; + } + }, + else => #error("OS not supported"), + } +} + const FileDescriptor = struct{ handle: system.FileDescriptor, diff --git a/lib/std/os/linux.nat b/lib/std/os/linux.nat index 946aa66..1d7aeb4 100644 --- a/lib/std/os/linux.nat +++ b/lib/std/os/linux.nat @@ -4,6 +4,379 @@ const stdin: FileDescriptor = 0; const stdout: FileDescriptor = 1; const stderr: FileDescriptor = 2; +const Syscall = switch (#import("builtin").cpu) { + .x86_64 => Syscall_x86_64, + else => #error("Architecture not supported"), +}; + +const ProcessId = s32; + +const Syscall_x86_64 = enum(usize) { + read = 0, + write = 1, + open = 2, + close = 3, + stat = 4, + fstat = 5, + lstat = 6, + poll = 7, + lseek = 8, + mmap = 9, + mprotect = 10, + munmap = 11, + brk = 12, + rt_sigaction = 13, + rt_sigprocmask = 14, + rt_sigreturn = 15, + ioctl = 16, + pread64 = 17, + pwrite64 = 18, + readv = 19, + writev = 20, + access = 21, + pipe = 22, + select = 23, + sched_yield = 24, + mremap = 25, + msync = 26, + mincore = 27, + madvise = 28, + shmget = 29, + shmat = 30, + shmctl = 31, + dup = 32, + dup2 = 33, + pause = 34, + nanosleep = 35, + getitimer = 36, + alarm = 37, + setitimer = 38, + getpid = 39, + sendfile = 40, + socket = 41, + connect = 42, + accept = 43, + sendto = 44, + recvfrom = 45, + sendmsg = 46, + recvmsg = 47, + shutdown = 48, + bind = 49, + listen = 50, + getsockname = 51, + getpeername = 52, + socketpair = 53, + setsockopt = 54, + getsockopt = 55, + clone = 56, + fork = 57, + vfork = 58, + execve = 59, + exit = 60, + wait4 = 61, + kill = 62, + uname = 63, + semget = 64, + semop = 65, + semctl = 66, + shmdt = 67, + msgget = 68, + msgsnd = 69, + msgrcv = 70, + msgctl = 71, + fcntl = 72, + flock = 73, + fsync = 74, + fdatasync = 75, + truncate = 76, + ftruncate = 77, + getdents = 78, + getcwd = 79, + chdir = 80, + fchdir = 81, + rename = 82, + mkdir = 83, + rmdir = 84, + creat = 85, + link = 86, + unlink = 87, + symlink = 88, + readlink = 89, + chmod = 90, + fchmod = 91, + chown = 92, + fchown = 93, + lchown = 94, + umask = 95, + gettimeofday = 96, + getrlimit = 97, + getrusage = 98, + sysinfo = 99, + times = 100, + ptrace = 101, + getuid = 102, + syslog = 103, + getgid = 104, + setuid = 105, + setgid = 106, + geteuid = 107, + getegid = 108, + setpgid = 109, + getppid = 110, + getpgrp = 111, + setsid = 112, + setreuid = 113, + setregid = 114, + getgroups = 115, + setgroups = 116, + setresuid = 117, + getresuid = 118, + setresgid = 119, + getresgid = 120, + getpgid = 121, + setfsuid = 122, + setfsgid = 123, + getsid = 124, + capget = 125, + capset = 126, + rt_sigpending = 127, + rt_sigtimedwait = 128, + rt_sigqueueinfo = 129, + rt_sigsuspend = 130, + sigaltstack = 131, + utime = 132, + mknod = 133, + uselib = 134, + personality = 135, + ustat = 136, + statfs = 137, + fstatfs = 138, + sysfs = 139, + getpriority = 140, + setpriority = 141, + sched_setparam = 142, + sched_getparam = 143, + sched_setscheduler = 144, + sched_getscheduler = 145, + sched_get_priority_max = 146, + sched_get_priority_min = 147, + sched_rr_get_interval = 148, + mlock = 149, + munlock = 150, + mlockall = 151, + munlockall = 152, + vhangup = 153, + modify_ldt = 154, + pivot_root = 155, + _sysctl = 156, + prctl = 157, + arch_prctl = 158, + adjtimex = 159, + setrlimit = 160, + chroot = 161, + sync = 162, + acct = 163, + settimeofday = 164, + mount = 165, + umount2 = 166, + swapon = 167, + swapoff = 168, + reboot = 169, + sethostname = 170, + setdomainname = 171, + iopl = 172, + ioperm = 173, + create_module = 174, + init_module = 175, + delete_module = 176, + get_kernel_syms = 177, + query_module = 178, + quotactl = 179, + nfsservctl = 180, + getpmsg = 181, + putpmsg = 182, + afs_syscall = 183, + tuxcall = 184, + security = 185, + gettid = 186, + readahead = 187, + setxattr = 188, + lsetxattr = 189, + fsetxattr = 190, + getxattr = 191, + lgetxattr = 192, + fgetxattr = 193, + listxattr = 194, + llistxattr = 195, + flistxattr = 196, + removexattr = 197, + lremovexattr = 198, + fremovexattr = 199, + tkill = 200, + time = 201, + futex = 202, + sched_setaffinity = 203, + sched_getaffinity = 204, + set_thread_area = 205, + io_setup = 206, + io_destroy = 207, + io_getevents = 208, + io_submit = 209, + io_cancel = 210, + get_thread_area = 211, + lookup_dcookie = 212, + epoll_create = 213, + epoll_ctl_old = 214, + epoll_wait_old = 215, + remap_file_pages = 216, + getdents64 = 217, + set_tid_address = 218, + restart_syscall = 219, + semtimedop = 220, + fadvise64 = 221, + timer_create = 222, + timer_settime = 223, + timer_gettime = 224, + timer_getoverrun = 225, + timer_delete = 226, + clock_settime = 227, + clock_gettime = 228, + clock_getres = 229, + clock_nanosleep = 230, + exit_group = 231, + epoll_wait = 232, + epoll_ctl = 233, + tgkill = 234, + utimes = 235, + vserver = 236, + mbind = 237, + set_mempolicy = 238, + get_mempolicy = 239, + mq_open = 240, + mq_unlink = 241, + mq_timedsend = 242, + mq_timedreceive = 243, + mq_notify = 244, + mq_getsetattr = 245, + kexec_load = 246, + waitid = 247, + add_key = 248, + request_key = 249, + keyctl = 250, + ioprio_set = 251, + ioprio_get = 252, + inotify_init = 253, + inotify_add_watch = 254, + inotify_rm_watch = 255, + migrate_pages = 256, + openat = 257, + mkdirat = 258, + mknodat = 259, + fchownat = 260, + futimesat = 261, + fstatat64 = 262, + unlinkat = 263, + renameat = 264, + linkat = 265, + symlinkat = 266, + readlinkat = 267, + fchmodat = 268, + faccessat = 269, + pselect6 = 270, + ppoll = 271, + unshare = 272, + set_robust_list = 273, + get_robust_list = 274, + splice = 275, + tee = 276, + sync_file_range = 277, + vmsplice = 278, + move_pages = 279, + utimensat = 280, + epoll_pwait = 281, + signalfd = 282, + timerfd_create = 283, + eventfd = 284, + fallocate = 285, + timerfd_settime = 286, + timerfd_gettime = 287, + accept4 = 288, + signalfd4 = 289, + eventfd2 = 290, + epoll_create1 = 291, + dup3 = 292, + pipe2 = 293, + inotify_init1 = 294, + preadv = 295, + pwritev = 296, + rt_tgsigqueueinfo = 297, + perf_event_open = 298, + recvmmsg = 299, + fanotify_init = 300, + fanotify_mark = 301, + prlimit64 = 302, + name_to_handle_at = 303, + open_by_handle_at = 304, + clock_adjtime = 305, + syncfs = 306, + sendmmsg = 307, + setns = 308, + getcpu = 309, + process_vm_readv = 310, + process_vm_writev = 311, + kcmp = 312, + finit_module = 313, + sched_setattr = 314, + sched_getattr = 315, + renameat2 = 316, + seccomp = 317, + getrandom = 318, + memfd_create = 319, + kexec_file_load = 320, + bpf = 321, + execveat = 322, + userfaultfd = 323, + membarrier = 324, + mlock2 = 325, + copy_file_range = 326, + preadv2 = 327, + pwritev2 = 328, + pkey_mprotect = 329, + pkey_alloc = 330, + pkey_free = 331, + statx = 332, + io_pgetevents = 333, + rseq = 334, + pidfd_send_signal = 424, + io_uring_setup = 425, + io_uring_enter = 426, + io_uring_register = 427, + open_tree = 428, + move_mount = 429, + fsopen = 430, + fsconfig = 431, + fsmount = 432, + fspick = 433, + pidfd_open = 434, + clone3 = 435, + close_range = 436, + openat2 = 437, + pidfd_getfd = 438, + faccessat2 = 439, + process_madvise = 440, + epoll_pwait2 = 441, + mount_setattr = 442, + quotactl_fd = 443, + landlock_create_ruleset = 444, + landlock_add_rule = 445, + landlock_restrict_self = 446, + memfd_secret = 447, + process_mrelease = 448, + futex_waitv = 449, + set_mempolicy_home_node = 450, + cachestat = 451, +}; + const FileDescriptor = s32; const ProtectionFlags = struct(u32) { @@ -38,17 +411,22 @@ 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) usize { - const result = #syscall(9, #cast(address), length, #cast(protection_flags), #cast(map_flags), fd, offset); + const result = #syscall(#cast(Syscall.mmap), #cast(address), length, #cast(protection_flags), #cast(map_flags), fd, offset); return result; } const munmap = fn(bytes_ptr: [&]const u8, bytes_len: usize) usize { - const result = #syscall(11, #cast(bytes_ptr), bytes_len); + const result = #syscall(#cast(Syscall.munmap), #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); + const result = #syscall(#cast(Syscall.readlink), #cast(file_path), #cast(bytes_ptr), bytes_len); + return result; +} + +const fork = fn() usize { + const result = #syscall(#cast(Syscall.fork)); return result; } diff --git a/lib/std/std.nat b/lib/std/std.nat index f4c52d6..7ddb972 100644 --- a/lib/std/std.nat +++ b/lib/std/std.nat @@ -2,6 +2,7 @@ comptime { _ = start; } +const build = #import("build.nat"); const builtin = #import("builtin.nat"); const os = #import("os.nat"); const start = #import("start.nat"); @@ -134,4 +135,10 @@ const copy_bytes = fn(destination: []u8, source: []const u8) void { } } +const Target = struct { + cpu: builtin.Cpu, + os: builtin.Os, + abi: builtin.Abi, +}; + var page_allocator = PageAllocator{}; diff --git a/test/fork/main.nat b/test/fork/main.nat new file mode 100644 index 0000000..8e7f968 --- /dev/null +++ b/test/fork/main.nat @@ -0,0 +1,15 @@ +const std = #import("std"); +const main = fn() s32 { + if (std.os.duplicate_process()) |pid| { + if (pid == 0) { + std.print(bytes = "Hello from child\n"); + std.os.exit(exit_code = 0); + } else { + std.print(bytes = "Hello from parent\n"); + return 0; + } + } else { + std.print(bytes = "Unable to create child process\n"); + return 1; + } +}