Browse Source

Merge branch 'master' of https://github.com/odin-lang/Odin

gingerBill 10 months ago
parent
commit
b839d06ac8

+ 14 - 2
base/runtime/core_builtin.odin

@@ -383,12 +383,23 @@ _make_dynamic_array_len_cap :: proc(array: ^Raw_Dynamic_Array, size_of_elem, ali
 	return
 }
 
-// `make_map` allocates and initializes a map. Like `new`, the first argument is a type, not a value.
+// `make_map` initializes a map with an allocator. Like `new`, the first argument is a type, not a value.
 // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
 //
 // Note: Prefer using the procedure group `make`.
 @(builtin, require_results)
-make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error {
+make_map :: proc($T: typeid/map[$K]$E, allocator := context.allocator) -> (m: T) {
+	m.allocator = allocator
+	return m
+}
+
+// `make_map_cap` initializes a map with an allocator and allocates space using `capacity`.
+// Like `new`, the first argument is a type, not a value.
+// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
+//
+// Note: Prefer using the procedure group `make`.
+@(builtin, require_results)
+make_map_cap :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error {
 	make_map_expr_error_loc(loc, capacity)
 	context.allocator = allocator
 
@@ -425,6 +436,7 @@ make :: proc{
 	make_dynamic_array_len,
 	make_dynamic_array_len_cap,
 	make_map,
+	make_map_cap,
 	make_multi_pointer,
 
 	make_soa_slice,

+ 3 - 2
build.bat

@@ -19,8 +19,8 @@ if "%VSCMD_ARG_TGT_ARCH%" neq "x64" (
 	)
 )
 
-for /f "usebackq tokens=1,2 delims=,=- " %%i in (`wmic os get LocalDateTime /value`) do @if %%i==LocalDateTime (
-	set CURR_DATE_TIME=%%j
+for /f %%i in ('powershell get-date -format "{yyyyMMdd}"') do (
+	set CURR_DATE_TIME=%%i
 )
 set curr_year=%CURR_DATE_TIME:~0,4%
 set curr_month=%CURR_DATE_TIME:~4,2%
@@ -70,6 +70,7 @@ set rc_flags=-nologo ^
 -DV1=%V1% -DV2=%V2% -DV3=%V3% -DV4=%V4% ^
 -DVF=%odin_version_full% -DNIGHTLY=%nightly%
 
+where /Q git.exe || goto skip_git_hash
 if not exist .git\ goto skip_git_hash
 for /f "tokens=1,2" %%i IN ('git show "--pretty=%%cd %%h" "--date=format:%%Y-%%m" --no-patch --no-notes HEAD') do (
 	set odin_version_raw=dev-%%i

+ 1 - 1
build_odin.sh

@@ -130,7 +130,7 @@ build_odin() {
 		EXTRAFLAGS="-O3"
 		;;
 	release-native)
-		if [ "$OS_ARCH" = "arm64" ]; then
+		if [ "$OS_ARCH" = "arm64" ] || [ "$OS_ARCH" = "aarch64" ]; then
 			# Use preferred flag for Arm (ie arm64 / aarch64 / etc)
 			EXTRAFLAGS="-O3 -mcpu=native"
 		else

+ 1 - 1
core/os/os2/allocators.odin

@@ -62,8 +62,8 @@ TEMP_ALLOCATOR_GUARD_END :: proc(temp: runtime.Arena_Temp, loc := #caller_locati
 
 @(deferred_out=TEMP_ALLOCATOR_GUARD_END)
 TEMP_ALLOCATOR_GUARD :: #force_inline proc(loc := #caller_location) -> (runtime.Arena_Temp, runtime.Source_Code_Location) {
-	tmp := temp_allocator_temp_begin(loc)
 	global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT
+	tmp := temp_allocator_temp_begin(loc)
 	return tmp, loc
 }
 

+ 2 - 0
core/os/os2/errors_linux.odin

@@ -162,6 +162,8 @@ _get_platform_error :: proc(errno: linux.Errno) -> Error {
 		return .Invalid_File
 	case .ENOMEM:
 		return .Out_Of_Memory
+	case .ENOSYS:
+		return .Unsupported
 	}
 
 	return Platform_Error(i32(errno))

+ 2 - 0
core/os/os2/errors_posix.odin

@@ -26,6 +26,8 @@ _get_platform_error :: proc() -> Error {
 		return .Invalid_File
 	case .ENOMEM:
 		return .Out_Of_Memory
+	case .ENOSYS:
+		return .Unsupported
 	case:
 		return Platform_Error(errno)
 	}

+ 1 - 1
core/os/os2/file_util.odin

@@ -164,7 +164,7 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
 }
 
 @(require_results)
-write_entire_file :: proc(name: string, data: []byte, perm: int, truncate := true) -> Error {
+write_entire_file :: proc(name: string, data: []byte, perm: int = 0o644, truncate := true) -> Error {
 	flags := O_WRONLY|O_CREATE
 	if truncate {
 		flags |= O_TRUNC

+ 1 - 1
core/os/os2/path_posix.odin

@@ -40,7 +40,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
 
 	internal_mkdir_all :: proc(path: string, perm: int) -> Error {
 		dir, file := filepath.split(path)
-		if file != path {
+		if file != path && dir != "/" {
 			if len(dir) > 1 && dir[len(dir) - 1] == '/' {
 				dir = dir[:len(dir) - 1]
 			}

+ 5 - 3
core/os/os2/pipe_posix.odin

@@ -49,7 +49,7 @@ _pipe_has_data :: proc(r: ^File) -> (ok: bool, err: Error) {
 	if r == nil || r.impl == nil {
 		return false, nil
 	}
-	fd := posix.FD((^File_Impl)(r.impl).fd)
+	fd := __fd(r)
 	poll_fds := []posix.pollfd {
 		posix.pollfd {
 			fd = fd,
@@ -57,8 +57,10 @@ _pipe_has_data :: proc(r: ^File) -> (ok: bool, err: Error) {
 		},
 	}
 	n := posix.poll(raw_data(poll_fds), u32(len(poll_fds)), 0)
-	if n != 1 {
+	if n < 0 {
 		return false, _get_platform_error()
+	} else if n != 1 {
+		return false, nil
 	}
 	pipe_events := poll_fds[0].revents
 	if pipe_events >= {.IN} {
@@ -68,4 +70,4 @@ _pipe_has_data :: proc(r: ^File) -> (ok: bool, err: Error) {
 		return false, .Broken_Pipe
 	}
 	return false, nil
-}
+}

+ 62 - 40
core/os/os2/process.odin

@@ -1,7 +1,7 @@
 package os2
 
 import "base:runtime"
-import "core:strings"
+
 import "core:time"
 
 /*
@@ -371,16 +371,18 @@ process_exec :: proc(
 	loc := #caller_location,
 ) -> (
 	state: Process_State,
-	stdout: []u8,
-	stderr: []u8,
+	stdout: []byte,
+	stderr: []byte,
 	err: Error,
 ) {
 	assert(desc.stdout == nil, "Cannot redirect stdout when it's being captured", loc)
 	assert(desc.stderr == nil, "Cannot redirect stderr when it's being captured", loc)
+
 	stdout_r, stdout_w := pipe() or_return
 	defer close(stdout_r)
 	stderr_r, stderr_w := pipe() or_return
-	defer close(stdout_w)
+	defer close(stderr_r)
+
 	process: Process
 	{
 		// NOTE(flysand): Make sure the write-ends are closed, regardless
@@ -392,45 +394,65 @@ process_exec :: proc(
 		desc.stderr = stderr_w
 		process = process_start(desc) or_return
 	}
-	stdout_builder := strings.builder_make(allocator) or_return
-	stderr_builder := strings.builder_make(allocator) or_return
-	read_data: for {
-		buf: [1024]u8
-		n: int
-		has_data: bool
-		hangup := false
-		has_data, err = pipe_has_data(stdout_r)
-		if has_data {
-			n, err = read(stdout_r, buf[:])
-			strings.write_bytes(&stdout_builder, buf[:n])
-		}
-		switch err {
-		case nil: // nothing
-		case .Broken_Pipe:
-			hangup = true
-		case:
-			return
-		}
-		has_data, err = pipe_has_data(stderr_r)
-		if has_data {
-			n, err = read(stderr_r, buf[:])
-			strings.write_bytes(&stderr_builder, buf[:n])
-		}
-		switch err {
-		case nil: // nothing
-		case .Broken_Pipe:
-			hangup = true
-		case:
-			return
+
+	{
+		stdout_b: [dynamic]byte
+		stdout_b.allocator = allocator
+		defer stdout = stdout_b[:]
+
+		stderr_b: [dynamic]byte
+		stderr_b.allocator = allocator
+		defer stderr = stderr_b[:]
+
+		buf: [1024]u8 = ---
+		
+		stdout_done, stderr_done, has_data: bool
+		for err == nil && (!stdout_done || !stderr_done) {
+			n := 0
+
+			if !stdout_done {
+				has_data, err = pipe_has_data(stdout_r)
+				if has_data {
+					n, err = read(stdout_r, buf[:])
+				}
+
+				switch err {
+				case nil:
+					_, err = append(&stdout_b, ..buf[:n])
+				case .EOF, .Broken_Pipe:
+					stdout_done = true
+					err = nil
+				}
+			}
+
+			if err == nil && !stderr_done {
+				n = 0
+				has_data, err = pipe_has_data(stderr_r)
+				if has_data {
+					n, err = read(stderr_r, buf[:])
+				}
+
+				switch err {
+				case nil:
+					_, err = append(&stderr_b, ..buf[:n])
+				case .EOF, .Broken_Pipe:
+					stderr_done = true
+					err = nil
+				}
+			}
 		}
-		if hangup {
-			break read_data
+	}
+
+	if err != nil {
+		state, _ = process_wait(process, timeout=0)
+		if !state.exited {
+			_ = process_kill(process)
+			state, _ = process_wait(process)
 		}
+		return
 	}
-	err = nil
-	stdout = transmute([]u8) strings.to_string(stdout_builder)
-	stderr = transmute([]u8) strings.to_string(stderr_builder)
-	state = process_wait(process) or_return
+
+	state, err = process_wait(process)
 	return
 }
 

+ 1 - 1
core/os/os2/process_linux.odin

@@ -523,7 +523,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 		write_errno_to_parent_and_abort :: proc(parent_fd: linux.Fd, errno: linux.Errno) -> ! {
 			error_byte: [1]u8 = { u8(errno) }
 			linux.write(parent_fd, error_byte[:])
-			intrinsics.trap()
+			linux.exit(126)
 		}
 
 		stdin_fd: linux.Fd

+ 1 - 2
core/os/os2/process_posix.odin

@@ -163,7 +163,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 			#assert(len(posix.Errno) < max(u8))
 			errno := u8(posix.errno())
 			posix.write(parent_fd, &errno, 1)
-			runtime.trap()
+			posix.exit(126)
 		}
 
 		null := posix.open("/dev/null", {.RDWR})
@@ -223,7 +223,6 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 			return
 		}
 
-		process.pid = int(pid)
 		process, _ = _process_open(int(pid), {})
 		return
 	}

+ 1 - 0
core/os/os2/process_posix_other.odin

@@ -15,6 +15,7 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error)
 }
 
 _process_open :: proc(pid: int, flags: Process_Open_Flags) -> (process: Process, err: Error) {
+	process.pid = pid
 	err = .Unsupported
 	return
 }

+ 21 - 17
core/os/os2/process_windows.odin

@@ -650,26 +650,30 @@ _build_command_line :: proc(command: []string, allocator: runtime.Allocator) ->
 			strings.write_byte(&builder, ' ')
 		}
 		j := 0
-		strings.write_byte(&builder, '"')
-		for j < len(arg) {
-			backslashes := 0
-			for j < len(arg) && arg[j] == '\\' {
-				backslashes += 1
+		if strings.contains_any(arg, "()[]{}^=;!'+,`~\" ") {
+			strings.write_byte(&builder, '"')
+			for j < len(arg) {
+				backslashes := 0
+				for j < len(arg) && arg[j] == '\\' {
+					backslashes += 1
+					j += 1
+				}
+				if j == len(arg) {
+					_write_byte_n_times(&builder, '\\', 2*backslashes)
+					break
+				} else if arg[j] == '"' {
+					_write_byte_n_times(&builder, '\\', 2*backslashes+1)
+					strings.write_byte(&builder, arg[j])
+				} else {
+					_write_byte_n_times(&builder, '\\', backslashes)
+					strings.write_byte(&builder, arg[j])
+				}
 				j += 1
 			}
-			if j == len(arg) {
-				_write_byte_n_times(&builder, '\\', 2*backslashes)
-				break
-			} else if arg[j] == '"' {
-				_write_byte_n_times(&builder, '\\', 2*backslashes+1)
-				strings.write_byte(&builder, '"')
-			} else {
-				_write_byte_n_times(&builder, '\\', backslashes)
-				strings.write_byte(&builder, arg[j])
-			}
-			j += 1
+			strings.write_byte(&builder, '"')
+		} else {
+			strings.write_string(&builder, arg)
 		}
-		strings.write_byte(&builder, '"')
 	}
 	return strings.to_string(builder)
 }

+ 19 - 3
core/sys/posix/sys_wait.odin

@@ -124,11 +124,11 @@ WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
 
 idtype_t :: enum c.int {
 	// Wait for any children and `id` is ignored.
-	P_ALL,
+	P_ALL  = _P_ALL,
 	// Wait for any child wiith a process group ID equal to `id`.
-	P_PID,
+	P_PID  = _P_PID,
 	// Wait for any child with a process group ID equal to `id`.
-	P_PGID,
+	P_PGID = _P_PGID,
 }
 
 Wait_Flag_Bits :: enum c.int {
@@ -166,6 +166,10 @@ when ODIN_OS == .Darwin {
 	WNOWAIT  :: 0x00000020
 	WSTOPPED :: 0x00000008
 
+	_P_ALL  :: 0
+	_P_PID  :: 1
+	_P_PGID :: 2
+
 	@(private)
 	_WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
 		return x & 0o177
@@ -221,6 +225,10 @@ when ODIN_OS == .Darwin {
 	WNOWAIT  :: 8
 	WSTOPPED :: 2
 
+	_P_ALL  :: 7
+	_P_PID  :: 0
+	_P_PGID :: 2
+
 	@(private)
 	_WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
 		return x & 0o177
@@ -275,6 +283,10 @@ when ODIN_OS == .Darwin {
 	WNOWAIT  :: 0x00010000
 	WSTOPPED :: 0x00000002
 
+	_P_ALL  :: 0
+	_P_PID  :: 1
+	_P_PGID :: 2
+
 	@(private)
 	_WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
 		return x & 0o177
@@ -330,6 +342,10 @@ when ODIN_OS == .Darwin {
 	WNOWAIT  :: 0x00010000
 	WSTOPPED :: 0x00000002
 
+	_P_ALL  :: 0
+	_P_PID  :: 2
+	_P_PGID :: 1
+
 	@(private)
 	_WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
 		return x & 0o177

+ 13 - 4
core/sys/windows/types.odin

@@ -253,8 +253,6 @@ FILE_GENERIC_WRITE: DWORD : STANDARD_RIGHTS_WRITE |
 	FILE_APPEND_DATA |
 	SYNCHRONIZE
 
-FILE_FLAG_OPEN_REPARSE_POINT: DWORD : 0x00200000
-FILE_FLAG_BACKUP_SEMANTICS: DWORD : 0x02000000
 SECURITY_SQOS_PRESENT: DWORD : 0x00100000
 
 FIONBIO: c_ulong : 0x8004667e
@@ -2222,11 +2220,22 @@ WAIT_OBJECT_0: DWORD : 0x00000000
 WAIT_TIMEOUT: DWORD : 258
 WAIT_FAILED: DWORD : 0xFFFFFFFF
 
+FILE_FLAG_WRITE_THROUGH: DWORD :       0x80000000
+FILE_FLAG_OVERLAPPED: DWORD :          0x40000000
+FILE_FLAG_NO_BUFFERING: DWORD :        0x20000000
+FILE_FLAG_RANDOM_ACCESS: DWORD :       0x10000000
+FILE_FLAG_SEQUENTIAL_SCAN: DWORD :     0x08000000
+FILE_FLAG_DELETE_ON_CLOSE: DWORD :     0x04000000
+FILE_FLAG_BACKUP_SEMANTICS: DWORD :    0x02000000
+FILE_FLAG_POSIX_SEMANTICS: DWORD :     0x01000000
+FILE_FLAG_SESSION_AWARE: DWORD :       0x00800000
+FILE_FLAG_OPEN_REPARSE_POINT: DWORD :  0x00200000
+FILE_FLAG_OPEN_NO_RECALL: DWORD :      0x00100000
+FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD : 0x00080000
+
 PIPE_ACCESS_INBOUND: DWORD : 0x00000001
 PIPE_ACCESS_OUTBOUND: DWORD : 0x00000002
 PIPE_ACCESS_DUPLEX: DWORD : 0x00000003
-FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD : 0x00080000
-FILE_FLAG_OVERLAPPED: DWORD : 0x40000000
 PIPE_WAIT: DWORD : 0x00000000
 PIPE_TYPE_BYTE: DWORD : 0x00000000
 PIPE_TYPE_MESSAGE: DWORD : 0x00000004

+ 0 - 5
src/check_expr.cpp

@@ -8795,11 +8795,6 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
 		return kind;
 	}
 
-	if (x.type == nullptr || x.type == t_invalid ||
-	    y.type == nullptr || y.type == t_invalid) {
-		return kind;
-	}
-
 	bool use_type_hint = type_hint != nullptr && (is_operand_nil(x) || is_operand_nil(y));
 
 	convert_to_typed(c, &x, use_type_hint ? type_hint : y.type);

+ 4 - 4
src/llvm_backend_expr.cpp

@@ -1225,10 +1225,10 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV
 			lbValue d3 = lb_emit_struct_ep(p, res.addr, 3);
 
 			if (immediate_type != ft) {
-				d0 = lb_emit_conv(p, d0, ft);
-				d1 = lb_emit_conv(p, d1, ft);
-				d2 = lb_emit_conv(p, d2, ft);
-				d3 = lb_emit_conv(p, d3, ft);
+				z0 = lb_emit_conv(p, z0, ft);
+				z1 = lb_emit_conv(p, z1, ft);
+				z2 = lb_emit_conv(p, z2, ft);
+				z3 = lb_emit_conv(p, z3, ft);
 			}
 
 			lb_emit_store(p, d0, z0);

+ 1 - 0
tests/core/normal.odin

@@ -33,6 +33,7 @@ download_assets :: proc() {
 @(require) import "net"
 @(require) import "odin"
 @(require) import "os"
+@(require) import "os/os2"
 @(require) import "path/filepath"
 @(require) import "reflect"
 @(require) import "runtime"

+ 25 - 0
tests/core/os/os2/process.odin

@@ -0,0 +1,25 @@
+package tests_core_os_os2
+
+import os "core:os/os2"
+import    "core:log"
+import    "core:testing"
+
+@(test)
+test_process_exec :: proc(t: ^testing.T) {
+	state, stdout, stderr, err := os.process_exec({
+		command = {"echo", "hellope"},
+	}, context.allocator)
+	defer delete(stdout)
+	defer delete(stderr)
+
+	if err == .Unsupported {
+		log.warn("process_exec unsupported")
+		return
+	}
+
+	testing.expect_value(t, state.exited,  true)
+	testing.expect_value(t, state.success, true)
+	testing.expect_value(t, err, nil)
+	testing.expect_value(t, string(stdout), "hellope\n")
+	testing.expect_value(t, string(stderr), "")
+}

+ 0 - 48
tests/core/sys/posix/posix.odin

@@ -1,8 +1,6 @@
 #+build darwin, freebsd, openbsd, netbsd
 package tests_core_posix
 
-import "base:runtime"
-
 import "core:log"
 import "core:path/filepath"
 import "core:strings"
@@ -217,52 +215,6 @@ test_termios :: proc(t: ^testing.T) {
 	testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._FFDLY),  posix.FFDLY)
 }
 
-@(test)
-test_signal :: proc(t: ^testing.T) {
-	@static tt: ^testing.T
-	tt = t
-
-	@static ctx: runtime.Context
-	ctx = context
-
-	act: posix.sigaction_t
-	act.sa_flags = {.SIGINFO, .RESETHAND}
-	act.sa_sigaction = handler
-	testing.expect_value(t, posix.sigaction(.SIGCHLD, &act, nil), posix.result.OK)
-
-	handler :: proc "c" (sig: posix.Signal, info: ^posix.siginfo_t, address: rawptr) {
-		context = ctx
-		testing.expect_value(tt, sig, posix.Signal.SIGCHLD)
-		testing.expect_value(tt, info.si_signo, posix.Signal.SIGCHLD)
-		testing.expect_value(tt, info.si_status, 69)
-		testing.expect_value(tt, info.si_code.chld, posix.CLD_Code.EXITED)
-	}
-
-	switch pid := posix.fork(); pid {
-	case -1:
-		log.errorf("fork() failure: %v", posix.strerror())
-	case 0:
-		posix.exit(69)
-	case:
-		for {
-			status: i32
-			res := posix.waitpid(pid, &status, {})
-			if res == -1 {
-				if !testing.expect_value(t, posix.errno(), posix.Errno.EINTR) {
-					break
-				}
-				continue
-			}
-
-			if posix.WIFEXITED(status) || posix.WIFSIGNALED(status) {
-				testing.expect(t, posix.WIFEXITED(status))
-				testing.expect(t, posix.WEXITSTATUS(status) == 69)
-				break
-			}
-        }
-	}
-}
-
 @(test)
 test_pthreads :: proc(t: ^testing.T) {
 	testing.set_fail_timeout(t, time.Second)