From 19963e4e19dc8ba84acd7ddacdb5c1d96c9cc291 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 19 Feb 2023 23:35:02 +0100 Subject: [PATCH] Fix attributes for nested bitstructs. Add some functions to std::net --- lib/std/net/inetaddr.c3 | 169 +++++++++++++++++++++++++++++++ src/compiler/parse_global.c | 1 + src/compiler/sema_decls.c | 35 ++++--- src/version.h | 2 +- test/unit/stdlib/net/inetaddr.c3 | 29 ++++++ 5 files changed, 221 insertions(+), 15 deletions(-) create mode 100644 lib/std/net/inetaddr.c3 create mode 100644 test/unit/stdlib/net/inetaddr.c3 diff --git a/lib/std/net/inetaddr.c3 b/lib/std/net/inetaddr.c3 new file mode 100644 index 000000000..b57aaed4c --- /dev/null +++ b/lib/std/net/inetaddr.c3 @@ -0,0 +1,169 @@ +module std::net; + + +struct InetAddress +{ + bool is_ipv6; + union + { + bitstruct ipv6 : char[16] @bigendian + { + ushort a : 0..15; + ushort b : 16..31; + ushort c : 32..47; + ushort d : 48..63; + ushort e : 64..79; + ushort f : 80..95; + ushort g : 96..111; + ushort h : 112..127; + } + bitstruct ip6 : char[16] @bigendian + { + uint128 val : 0..127; + } + + bitstruct ipv4 : char[16] @bigendian + { + char a : 96..103; + char b : 104..111; + char c : 112..119; + char d : 120..127; + } + bitstruct ip4 : char[16] @bigendian + { + uint val : 96..127; + } + } +} + +fn InetAddress! ipv4_from_str(String s) +{ + InetAddress addr; + int element; + int current = -1; + foreach (c : s) + { + if (c == '.') + { + if (current < 0) return NetError.INVALID_IP_STRING!; + if (current > 255) return NetError.INVALID_IP_STRING!; + switch (element) + { + case 0: addr.ipv4.a = (char)current; + case 1: addr.ipv4.b = (char)current; + case 2: addr.ipv4.c = (char)current; + default: return NetError.INVALID_IP_STRING!; + } + current = -1; + element++; + continue; + } + if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING!; + if (current < 0) + { + current = c - '0'; + continue; + } + current = current * 10 + c - '0'; + } + if (element != 3 || current < 0 || current > 255) return NetError.INVALID_IP_STRING!; + addr.ipv4.d = (char)current; + return addr; +} + +fn bool InetAddress.is_loopback(InetAddress* addr) +{ + if (addr.is_ipv6) + { + return addr.ip6.val == 1; + } + return addr.ipv4.a == 127; +} + +fn bool InetAddress.is_any_local(InetAddress* addr) +{ + if (addr.is_ipv6) + { + return addr.ip6.val == 0; + } + return addr.ip4.val == 0; +} + +fn bool InetAddress.is_link_local(InetAddress* addr) +{ + if (addr.is_ipv6) + { + return addr.ipv6.a == 0xfa && (addr.ipv6.b & 0xc0) == 0x80; + } + return addr.ipv4.a == 169 && addr.ipv4.b == 254; +} + +fn bool InetAddress.is_site_local(InetAddress* addr) +{ + if (addr.is_ipv6) + { + return addr.ipv6.a == 0xfe && (addr.ipv6.b & 0xc0) == 0xc0; + } + // 10/8 172.16/12 192.168/16 + switch + { + case addr.ipv4.a == 10: + case addr.ipv4.a == 172 && (addr.ipv4.b & 0xF0) == 16: + case addr.ipv4.a == 192 && addr.ipv4.b == 168: + return true; + default: + return false; + } +} + +fn bool InetAddress.is_multicast(InetAddress* addr) +{ + if (addr.is_ipv6) + { + return addr.ipv6.a == 0xff; + } + return addr.ip4.val & 0xf0000000 == 0xe0000000; +} + +fn bool InetAddress.is_multicast_global(InetAddress* addr) +{ + if (addr.is_ipv6) + { + return addr.ipv6.a == 0xff && (addr.ipv6.b & 0x0f) == 0x0e; + } + return addr.ipv4.a >= 224 && addr.ipv4.a <= 238 + && !(addr.ipv4.a == 224 && addr.ipv4.b == 0 && addr.ipv4.c == 0); +} + +fn bool InetAddress.is_multicast_node_local(InetAddress* addr) +{ + if (!addr.is_ipv6) return false; + return addr.ipv6.a == 0xff && addr.ipv6.b & 0x0f == 0x01; +} + +fn bool InetAddress.is_multicast_site_local(InetAddress* addr) +{ + if (addr.is_ipv6) + { + return addr.ipv6.a == 0xff && addr.ipv6.b & 0x0f == 0x05; + } + return addr.ipv4.a == 239 && addr.ipv4.b == 255; +} + +fn bool InetAddress.is_multicast_org_local(InetAddress* addr) +{ + if (addr.is_ipv6) + { + return addr.ipv6.a == 0xff && addr.ipv6.b & 0x0f == 0x08; + } + return addr.ipv4.a == 239 && addr.ipv4.b >= 192 && addr.ipv4.b <= 195; +} + +fn bool InetAddress.is_multicast_link_local(InetAddress* addr) +{ + if (addr.is_ipv6) + { + return addr.ipv6.a == 0xff && (addr.ipv6.b & 0x0f) == 0x02; + } + return addr.ipv4.a == 224 && addr.ipv4.b == 0 && addr.ipv4.c == 0; +} diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 07b868644..e08604c78 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -1593,6 +1593,7 @@ bool parse_struct_body(ParseContext *c, Decl *parent) { TRY_CONSUME_OR_RET(TOKEN_COLON, "':' followed by bitstruct type (e.g. 'int') was expected here.", poisoned_decl); ASSIGN_TYPE_OR_RET(member->bitstruct.base_type, parse_type(c), poisoned_decl); + if (!parse_attributes_for_global(c, member)) return decl_poison(parent); if (!parse_bitstruct_body(c, member)) return decl_poison(parent); } else diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 7a26b967a..91d77a051 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -2306,7 +2306,28 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl) } global_context.test_func = decl; } + bool is_test = decl->func_decl.attr_test; Signature *sig = &decl->func_decl.signature; + if (is_test) + { + if (vec_size(sig->params)) + { + SEMA_ERROR(sig->params[0], "'@test' functions may not take any parameters."); + return false; + } + TypeInfo *rtype_info = type_infoptr(sig->rtype); + if (!sema_resolve_type_info(context, rtype_info)) return false; + if (type_no_optional(rtype_info->type) != type_void) + { + SEMA_ERROR(rtype_info, "'@test' functions may only return 'void' or 'void!'."); + return false; + } + if (rtype_info->type == type_void) + { + rtype_info->type = type_get_optional(rtype_info->type); + } + } + Type *func_type = sema_analyse_function_signature(context, decl, sig->abi, sig, true); decl->type = func_type; if (!func_type) return decl_poison(decl); @@ -2329,7 +2350,6 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl) return decl_poison(decl); } } - bool is_test = decl->func_decl.attr_test; if (decl->func_decl.type_parent) { if (is_test) SEMA_ERROR(decl, "Methods may not be annotated @test."); @@ -2343,19 +2363,6 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl) if (!sema_analyse_main_function(context, decl)) return decl_poison(decl); } decl_set_external_name(decl); - if (is_test) - { - if (vec_size(sig->params)) - { - SEMA_ERROR(sig->params[0], "'@test' functions may not take any parameters."); - return false; - } - if (type_no_optional(rtype) != type_void) - { - SEMA_ERROR(rtype_info, "'@test' functions may only return 'void' or 'void!'."); - return false; - } - } } bool pure = false; diff --git a/src/version.h b/src/version.h index 7f661ba69..0d1aea936 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.76" \ No newline at end of file +#define COMPILER_VERSION "0.4.77" \ No newline at end of file diff --git a/test/unit/stdlib/net/inetaddr.c3 b/test/unit/stdlib/net/inetaddr.c3 new file mode 100644 index 000000000..dffae8e54 --- /dev/null +++ b/test/unit/stdlib/net/inetaddr.c3 @@ -0,0 +1,29 @@ +module inetaddrtest; +import std::net; + +fn void test_ipv4() @test +{ + InetAddress foo = { .ipv4 = { 127, 0, 0, 0 } }; + assert(foo.ip4.val == 2130706432); + assert(foo.is_loopback()); + +} + +fn void! test_ipv4_parse() @test +{ + InetAddress a = net::ipv4_from_str("127.0.0.1")?; + assert(a.ipv4.a == 127 && a.ipv4.b == 0 && a.ipv4.c == 0 && a.ipv4.d == 1); + a = net::ipv4_from_str("255.254.253.255")?; + assert(a.ipv4.a == 255 && a.ipv4.b == 254 && a.ipv4.c == 253 && a.ipv4.d == 255); + assert(catch(net::ipv4_from_str(".1.1.1.1"))); + assert(catch(net::ipv4_from_str("1..1.1"))); + assert(catch(net::ipv4_from_str("1..1.1.1"))); + assert(catch(net::ipv4_from_str("1.1.1.256"))); + assert(catch(net::ipv4_from_str("256.1.1.1"))); +} + +fn void test_ipv6() @test +{ + InetAddress foo = { .ipv6 = { 0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888 } }; + assert(foo.ip6.val == 42541956123769884636017138956568135816); +}