diff --git a/lib/std/libc/os/posix.c3 b/lib/std/libc/os/posix.c3 index 896399d1d..643320d0a 100644 --- a/lib/std/libc/os/posix.c3 +++ b/lib/std/libc/os/posix.c3 @@ -1,5 +1,7 @@ module libc @if(env::POSIX); +extern fn isz recv(Fd socket, void *buffer, usz length, CInt flags); +extern fn isz send(Fd socket, void *buffer, usz length, CInt flags); extern fn void* dlopen(ZString path, int flags); extern fn CInt dlclose(void*); @@ -188,3 +190,4 @@ struct Termios { Speed c_ispeed; Speed c_ospeed; } + diff --git a/lib/std/libc/os/win32.c3 b/lib/std/libc/os/win32.c3 index 35175056f..c8fd0146d 100644 --- a/lib/std/libc/os/win32.c3 +++ b/lib/std/libc/os/win32.c3 @@ -1,5 +1,5 @@ module libc @if(env::WIN32); - +import std::os::win32; extern fn CFile __acrt_iob_func(CInt c); extern fn CInt _close(Fd fd); def close = _close; @@ -15,11 +15,13 @@ extern fn Time_t _mkgmtime64(Tm* timeptr); def timegm = _mkgmtime64; extern fn Time_t _mktime64(Tm *timeptr); def mktime = _mktime64; extern fn usz _msize(void* ptr); extern fn CInt _read(Fd fd, void* buffer, CUInt buffer_size); -extern fn CInt _setjmp(void* frameptr, JmpBuf* buffer) @if(env::WIN32); +extern fn CInt _setjmp(void* frameptr, JmpBuf* buffer); extern fn CFile _wfopen(WString, WString); extern fn CFile _wfreopen(WString, WString, CFile); extern fn CInt _write(Fd fd, void* buffer, CUInt count); extern fn CInt _wremove(WString); +extern fn int recv(Win32_SOCKET s, void* buf, int len, int flags); +extern fn int send(Win32_SOCKET s, void* buf, int len, int flags); struct SystemInfo { diff --git a/lib/std/net/os/posix.c3 b/lib/std/net/os/posix.c3 index 060a00c48..506f270e9 100644 --- a/lib/std/net/os/posix.c3 +++ b/lib/std/net/os/posix.c3 @@ -16,11 +16,11 @@ struct Posix_pollfd def Posix_nfds_t = CUInt; extern fn CInt connect(NativeSocket socket, SockAddrPtr address, Socklen_t address_len); -extern fn NativeSocket socket(AIFamily af, AISockType type, AIProtocol ip_protocol) @extern("socket"); -extern fn int fcntl(NativeSocket socket, int cmd, ...) @extern("fcntl"); -extern fn CInt bind(NativeSocket socket, SockAddrPtr address, Socklen_t address_len) @extern("bind"); -extern fn CInt listen(NativeSocket socket, CInt backlog) @extern("listen"); -extern fn NativeSocket accept(NativeSocket socket, SockAddrPtr address, Socklen_t* address_len) @extern("accept"); +extern fn NativeSocket socket(AIFamily af, AISockType type, AIProtocol ip_protocol); +extern fn int fcntl(NativeSocket socket, int cmd, ...); +extern fn CInt bind(NativeSocket socket, SockAddrPtr address, Socklen_t address_len); +extern fn CInt listen(NativeSocket socket, CInt backlog); +extern fn NativeSocket accept(NativeSocket socket, SockAddrPtr address, Socklen_t* address_len); extern fn CInt poll(Posix_pollfd* fds, Posix_nfds_t nfds, CInt timeout); const CUShort POLLIN = 0x0001; @@ -55,6 +55,11 @@ fn anyfault socket_error() return convert_error(libc::errno()); } +macro bool NativeSocket.is_valid(self) +{ + return (iptr)self >= 0; +} + macro void! NativeSocket.close(self) { if (libc::close(self)) diff --git a/lib/std/net/os/win32.c3 b/lib/std/net/os/win32.c3 index 2268859a1..9c9079230 100644 --- a/lib/std/net/os/win32.c3 +++ b/lib/std/net/os/win32.c3 @@ -12,7 +12,7 @@ const int FIONREAD = 1074030207; const int FIONBIO = -2147195266; const int FIOASYNC = -2147195267; -distinct NativeSocket = uptr; +distinct NativeSocket = inline Win32_SOCKET; extern fn CInt ioctlsocket(NativeSocket, CLong cmd, CULong *argp); extern fn WSAError closesocket(NativeSocket); @@ -22,6 +22,11 @@ extern fn int bind(NativeSocket, SockAddrPtr address, Socklen_t address_len); extern fn int listen(NativeSocket, int backlog); extern fn NativeSocket accept(NativeSocket, SockAddrPtr address, Socklen_t* address_len); +macro bool NativeSocket.is_valid(self) +{ + return self != (NativeSocket)(uptr)-1; +} + fn void! NativeSocket.set_non_blocking(self, bool non_blocking) { if (ioctlsocket(self, win32::FIONBIO, &&(CULong)non_blocking)) diff --git a/lib/std/net/socket.c3 b/lib/std/net/socket.c3 index bec049ded..a4c109bd0 100644 --- a/lib/std/net/socket.c3 +++ b/lib/std/net/socket.c3 @@ -15,7 +15,7 @@ macro void @loop_over_ai(AddrInfo* ai; @body(NativeSocket fd, AddrInfo* ai)) while (ai) { NativeSocket sockfd = os::socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol); - if (sockfd > 0) + if (sockfd.is_valid()) { @body(sockfd, ai); } @@ -120,8 +120,12 @@ fn bool! Socket.get_option(&self, SocketOption option) fn usz! Socket.read(&self, char[] bytes) @dynamic { - isz n = libc::read((Fd)self.sock, bytes.ptr, bytes.len); - if (n < 0) return NetError.READ_FAILED?; +$if env::WIN32: + isz n = libc::recv(self.sock, bytes.ptr, (int)bytes.len, 0); +$else + isz n = libc::recv(self.sock, bytes.ptr, bytes.len, 0); +$endif + if (n < 0) return os::socket_error()?; return (usz)n; } @@ -129,8 +133,12 @@ fn char! Socket.read_byte(&self) @dynamic => io::@read_byte_using_read(self); fn usz! Socket.write(&self, char[] bytes) @dynamic { - isz n = libc::write((Fd)self.sock, bytes.ptr, bytes.len); - if (n < 0) return NetError.WRITE_FAILED?; +$if env::WIN32: + isz n = libc::send(self.sock, bytes.ptr, (int)bytes.len, 0); +$else + isz n = libc::send(self.sock, bytes.ptr, bytes.len, 0); +$endif + if (n < 0) return os::socket_error()?; return (usz)n; } diff --git a/lib/std/net/tcp.c3 b/lib/std/net/tcp.c3 index 8860643bb..15a2dde85 100644 --- a/lib/std/net/tcp.c3 +++ b/lib/std/net/tcp.c3 @@ -44,7 +44,7 @@ fn TcpSocket! accept(TcpServerSocket* server_socket) { TcpSocket socket; socket.sock = os::accept(server_socket.sock, (SockAddrPtr)&socket.ai_addr_storage, &socket.ai_addrlen); - if (socket.sock < 0) return NetError.ACCEPT_FAILED?; + if (!socket.sock.is_valid()) return NetError.ACCEPT_FAILED?; return socket; } diff --git a/releasenotes.md b/releasenotes.md index 9682586b7..bdd191d46 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -46,10 +46,13 @@ - Variable in if-try / if-catch cannot be a reused variable name. - Vararg interfaces were broken. - LLVM codegen for constants in enums could fail. +- Fixes to the socket functions. +- Improved output when pointer is out of range. +- Better error when casting to a distinct fails. ### Stdlib changes -None +- `send` and `recv` added to `libc` for Posix / Win32. ## 0.6.1 Change list diff --git a/src/compiler/bigint.c b/src/compiler/bigint.c index 86c58d08c..0188caff2 100644 --- a/src/compiler/bigint.c +++ b/src/compiler/bigint.c @@ -39,7 +39,7 @@ UNUSED static char digit_to_char(uint8_t digit, bool upper) #define LO32(_x) ((_x) & 0xffffffff) #define ISNEG(_x) (((uint64_t)_x) >> 63) -char *i128_to_string(Int128 op, uint64_t base, bool is_signed) +char *i128_to_string(Int128 op, uint64_t base, bool is_signed, bool use_prefix) { assert(base >= 2 && base <= 16); static char digits[16] = "0123456789ABCDEF"; @@ -54,9 +54,29 @@ char *i128_to_string(Int128 op, uint64_t base, bool is_signed) *(loc++) = digits[rem.low]; op = i128_udiv(op, base_div); } while (!i128_is_zero(op)); - char *res = malloc_string((size_t)(loc - buffer + 2)); + char *res = malloc_string((size_t)(loc - buffer + 4)); char *c = res; if (add_minus) *(c++) = '-'; + if (use_prefix) + { + switch (base) + { + case 2: + *(c++) = '0'; + *(c++) = 'b'; + break; + case 8: + *(c++) = '0'; + *(c++) = 'o'; + break; + case 16: + *(c++) = '0'; + *(c++) = 'x'; + break; + default: + break; + } + } while (loc > buffer) { *(c++) = *(--loc); @@ -65,9 +85,10 @@ char *i128_to_string(Int128 op, uint64_t base, bool is_signed) return res; } -char *int_to_str(Int i, int radix) + +char *int_to_str(Int i, int radix, bool use_prefix) { - return i128_to_string(i.i, (uint64_t)radix, type_kind_is_signed(i.type)); + return i128_to_string(i.i, (uint64_t) radix, type_kind_is_signed(i.type), use_prefix); } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 09cccb494..5e07a4320 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2097,7 +2097,7 @@ Int int_shr64(Int op, uint64_t); Int int_shl64(Int op, uint64_t); Real int_to_real(Int op); Int int_from_real(Real d, TypeKind type); -char *int_to_str(Int i, int radix); +char *int_to_str(Int i, int radix, bool use_prefix); bool i128_can_convert_from_double(double x); bool i128_can_convert_from_double_signed(double x); Int128 i128_from_double(double x); @@ -2117,7 +2117,7 @@ Int128 i128_not(Int128 op1); Int128 i128_mult(Int128 op1, Int128 op2); Int128 i128_mult64(Int128 op1, uint64_t op2); Int128 i128_from_str(const char *str); -char *i128_to_string(Int128 op, uint64_t base, bool is_signed); +char *i128_to_string(Int128 op, uint64_t base, bool is_signed, bool use_prefix); bool i128_is_neg(Int128 op); CmpRes i128_ucomp(Int128 op1, Int128 op2); CmpRes i128_scomp(Int128 op1, Int128 op2); diff --git a/src/compiler/headers.c b/src/compiler/headers.c index d1c42d16f..41715436a 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -623,7 +623,7 @@ static void header_gen_global_var(HeaderContext *c, Decl *decl, bool fn_globals, switch (init->const_expr.const_kind) { case CONST_INTEGER: - PRINTF("%s\n", int_to_str(init->const_expr.ixx, 10)); + PRINTF("%s\n", int_to_str(init->const_expr.ixx, 10, false)); return; case CONST_FLOAT: PRINTF("%.15g\n", init->const_expr.fxx.f); diff --git a/src/compiler/number.c b/src/compiler/number.c index 4b87df189..40b5363be 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -295,7 +295,7 @@ const char *expr_const_to_error_string(const ExprConst *expr) case CONST_BOOL: return expr->b ? "true" : "false"; case CONST_INTEGER: - return int_to_str(expr->ixx, 10); + return int_to_str(expr->ixx, 10, false); case CONST_FLOAT: return str_printf("%g", expr->fxx.f); case CONST_STRING: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 067ada9db..651ad4ffa 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -1542,12 +1542,12 @@ EXIT: if (type_bits) { PRINT_ERROR_HERE("'%s' does not fit in a '%c%d' literal.", - i128_to_string(i, radix, true), is_unsigned ? 'u' : 'i', type_bits); + i128_to_string(i, radix, true, false), is_unsigned ? 'u' : 'i', type_bits); } else { PRINT_ERROR_HERE("'%s' does not fit in an %s literal.", - i128_to_string(i, radix, true), is_unsigned ? "unsigned int" : "int"); + i128_to_string(i, radix, true, false), is_unsigned ? "unsigned int" : "int"); } return poisoned_expr; } diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index ba15e1fa7..162af18a6 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -170,7 +170,7 @@ static inline bool parse_asm_scale(ParseContext *c, ExprAsmArg *asm_arg) Int i = value->const_expr.ixx; if (i.i.high) { - PRINT_ERROR_HERE("The value is too high for a scale: %s", int_to_str(i, 10)); + PRINT_ERROR_HERE("The value is too high for a scale: %s", int_to_str(i, 10, false)); return false; } switch (i.i.low) diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 2d9507ba7..a53491274 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -573,7 +573,8 @@ static bool sema_error_const_int_out_of_range(CastContext *cc, Expr *expr, Expr expr->const_expr.enum_err_val->var.index, type_quoted_error_string(to_type)); } - const char *error_value = expr->const_expr.is_hex ? int_to_str(expr->const_expr.ixx, 16) : expr_const_to_error_string(&expr->const_expr); + const char *error_value = expr->const_expr.is_hex ? int_to_str(expr->const_expr.ixx, 16, true) + : expr_const_to_error_string(&expr->const_expr); RETURN_CAST_ERROR(problem, "The value '%s' is out of range for %s, so you need an explicit cast to truncate the value.", error_value, type_quoted_error_string(to_type)); } @@ -727,11 +728,11 @@ static bool rule_int_to_ptr(CastContext *cc, bool is_explicit, bool is_silent) if (!is_explicit) return sema_cast_error(cc, true, is_silent); // For if the type doesn't fit, insert an error. - if (!int_fits(expr->const_expr.ixx, type_uptr->canonical->type_kind)) + Int i = expr->const_expr.ixx; + if (!int_fits(i, type_uptr->canonical->type_kind)) { if (is_silent) return false; - RETURN_CAST_ERROR(expr, "'0x%s' does not fit in a pointer.", int_to_str(expr->const_expr.ixx, 16)); - return false; + RETURN_CAST_ERROR(expr, "'%s' does not fit in a pointer.", int_to_str(i, 16, true)); } return true; } @@ -1231,10 +1232,12 @@ static bool rule_to_distinct(CastContext *cc, bool is_explicit, bool is_silent) { cc->to = flat; cc->to_group = flat_group; - if (cast_is_allowed(cc, is_explicit, true)) return true; - if (is_silent) return false; - bool may_explicit = !is_explicit && cast_is_allowed(cc, true, true); - return sema_cast_error(cc, may_explicit, is_silent); + + // If it's silent or explicit, just run it: + if (is_silent || is_explicit) return cast_is_allowed(cc, is_explicit, is_silent); + // Loud and implicit: + if (cast_is_allowed(cc, false, true)) return true; + return sema_cast_error(cc, cast_is_allowed(cc, true, true), is_silent); } cc->to = flat; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 2f123ca9a..672e03b93 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1518,7 +1518,7 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *era { SEMA_ERROR(enum_value, "The enum value would implicitly be %s which does not fit in %s.", - i128_to_string(value, 10, type_is_signed(flat_underlying_type)), + i128_to_string(value, 10, type_is_signed(flat_underlying_type), false), type_quoted_error_string(type)); return false; } @@ -4011,7 +4011,7 @@ static bool sema_generate_parameterized_name_to_scratch(SemaContext *context, Mo char *maybe_neg = &scratch_buffer.str[scratch_buffer.len]; if (type->type_kind == TYPE_I128 || type->type_kind == TYPE_U128) { - char *str = int_to_str(param->const_expr.ixx, 10); + char *str = int_to_str(param->const_expr.ixx, 10, false); scratch_buffer_append(str); } else diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 76ef613d2..2fdfd00e7 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -227,7 +227,7 @@ static Decl **sema_run_exec(CompilationUnit *unit, Decl *decl) scratch_buffer_append_double(arg->const_expr.fxx.f); continue; case CONST_INTEGER: - scratch_buffer_append(int_to_str(arg->const_expr.ixx, 10)); + scratch_buffer_append(int_to_str(arg->const_expr.ixx, 10, false)); continue; case CONST_BOOL: scratch_buffer_append(arg->const_expr.b ? "true" : "false"); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index c0c5a9d2a..65f9a96a3 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -2198,8 +2198,8 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type sema_error_at(context, extend_span_with_token(expr->span, to_expr->span), "The range is not valid because the first value (%s) is greater than the second (%s). " "It would work if you swapped their order.", - int_to_str(const_expr->ixx, 10), - int_to_str(to_const_expr->ixx, 10)); + int_to_str(const_expr->ixx, 10, false), + int_to_str(to_const_expr->ixx, 10, false)); return false; } Int128 range = int_sub(to_const_expr->ixx, const_expr->ixx).i; @@ -2774,7 +2774,7 @@ bool sema_analyse_ct_echo_stmt(SemaContext *context, Ast *statement) printf("%f\n", (double)message->const_expr.fxx.f); break; case CONST_INTEGER: - puts(int_to_str(message->const_expr.ixx, 10)); + puts(int_to_str(message->const_expr.ixx, 10, false)); break; case CONST_BOOL: puts(message->const_expr.b ? "true" : "false"); diff --git a/src/compiler_tests/tests.c b/src/compiler_tests/tests.c index f3a661ede..ba553479e 100644 --- a/src/compiler_tests/tests.c +++ b/src/compiler_tests/tests.c @@ -153,10 +153,12 @@ void test128() addres = i128_udiv(i128(UINT64_MAX, 0), i128(1, 0)); TEST_ASSERT(addres.low == UINT64_MAX && addres.high == 0, "Div failed"); addres = i128_sdiv(i128(UINT64_MAX - 1, UINT64_MAX - 1), i128(1, 0)); - TEST_ASSERTF(addres.low == UINT64_MAX && addres.high == UINT64_MAX, "Div failed %s", i128_to_string(addres, 10, true)); + TEST_ASSERTF(addres.low == UINT64_MAX && addres.high == UINT64_MAX, "Div failed %s", i128_to_string(addres, 10, + true, false)); addres = i128_sdiv(i128(2, 0), i128(UINT64_MAX - 1, UINT64_MAX - 1)); printf("-- i128 Div okfefe %x.\n", (unsigned)-2); - TEST_ASSERTF(addres.low == UINT64_MAX && addres.high == UINT64_MAX, "Div failed: %s %llx, %llx", i128_to_string(addres, 10, true), (unsigned long long)addres.high, (unsigned long long)addres.low); + TEST_ASSERTF(addres.low == UINT64_MAX && addres.high == UINT64_MAX, "Div failed: %s %llx, %llx", i128_to_string( + addres, 10, true, false), (unsigned long long)addres.high, (unsigned long long)addres.low); printf("-- i128 Div ok.\n");