mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix attributes for nested bitstructs. Add some functions to std::net
This commit is contained in:
169
lib/std/net/inetaddr.c3
Normal file
169
lib/std/net/inetaddr.c3
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.76"
|
||||
#define COMPILER_VERSION "0.4.77"
|
||||
29
test/unit/stdlib/net/inetaddr.c3
Normal file
29
test/unit/stdlib/net/inetaddr.c3
Normal file
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user