harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

06-structs.ha (7358B)


      1 use rt::{compile, exited, EXIT_SUCCESS};
      2 
      3 fn padding() void = {
      4 	assert(size(struct { x: i32, y: i32 }) == 8);
      5 	assert(size(struct { x: i32, y: i64 }) == 16);
      6 	assert(size(union { x: i8, y: i16, z: i32 }) == 4);
      7 	assert(align(struct { x: i32, y: i32 }) == 4);
      8 	assert(align(struct { x: i32, y: i64 }) == 8);
      9 	assert(align(union { x: i8, y: i16, z: i32 }) == 4);
     10 
     11 	const s = struct {
     12 		x: i8 = 10,
     13 		y: i16 = 20,
     14 		z: i32 = 30,
     15 		q: i64 = 40,
     16 	};
     17 	assert(&s.x: uintptr: size % 1 == 0);
     18 	assert(&s.y: uintptr: size % 2 == 0);
     19 	assert(&s.z: uintptr: size % 4 == 0);
     20 	assert(&s.q: uintptr: size % 8 == 0);
     21 };
     22 
     23 fn storage() void = {
     24 	let coords = struct { x: i32 = 10, y: i32 = 20 };
     25 	let ptr = &coords: *[*]i32;
     26 	assert(ptr[0] == 10 && ptr[1] == 20);
     27 };
     28 
     29 fn assignment() void = {
     30 	let coords = struct { x: int = 20, y: int = 30 };
     31 	coords.x = 40;
     32 	coords.y = 50;
     33 	assert(coords.x == 40 && coords.y == 50);
     34 	coords = struct { x: int = 60, y: int = 70 };
     35 	assert(coords.x == 60 && coords.y == 70);
     36 };
     37 
     38 fn deref() void = {
     39 	let coords = struct { x: int = 20, y: int = 30 };
     40 	let a = &coords;
     41 	assert(a.x == 20 && a.y == 30);
     42 	let b = &a;
     43 	assert(b.x == 20 && b.y == 30);
     44 	let c = &b;
     45 	assert(c.x == 20 && c.y == 30);
     46 	c.x = 42;
     47 	c.y = 96;
     48 	assert(coords.x == 42 && coords.y == 96);
     49 };
     50 
     51 type embedded = struct {
     52 	foo: u8,
     53 };
     54 
     55 type embed1 = struct {
     56 	embedded,
     57 	struct {
     58 		bar: u8,
     59 		baz: u64,
     60 	},
     61 };
     62 
     63 type embed2 = struct {
     64 	struct {
     65 		bar: u8,
     66 		baz: u64,
     67 	},
     68 	embedded,
     69 };
     70 
     71 fn nested() void = {
     72 	let s = embed1 {
     73 		foo = 42,
     74 		bar = 69,
     75 		baz = 1337,
     76 	};
     77 	assert(offset(s.foo) == 0 && offset(s.bar) == 8 && offset(s.baz) == 16);
     78 	assert(s.foo == 42 && s.bar == 69 && s.baz == 1337);
     79 	let s = embed2 {
     80 		foo = 42,
     81 		bar = 69,
     82 		baz = 1337,
     83 	};
     84 	assert(offset(s.bar) == 0 && offset(s.baz) == 8 && offset(s.foo) == 16);
     85 	assert(s.foo == 42 && s.bar == 69 && s.baz == 1337);
     86 
     87 	let s = struct {
     88 		x: int = 10,
     89 		y: struct {
     90 			z: int,
     91 			q: int,
     92 			a: struct { b: int, c: int },
     93 		} = struct {
     94 			z: int = 20,
     95 			q: int = 30,
     96 			a: struct { b: int, c: int } = struct {
     97 				b: int = 42, c: int = 24,
     98 			},
     99 		},
    100 	};
    101 	assert(s.x == 10);
    102 	assert(s.y.z == 20);
    103 	assert(s.y.q == 30);
    104 	assert(s.y.a.b == 42);
    105 	assert(s.y.a.c == 24);
    106 	assert(&s.y: uintptr == &s.y.z: uintptr);
    107 
    108 	s.x = 1337;
    109 	assert(s.x == 1337);
    110 
    111 	s.y.a = struct { b: int = 1337, c: int = 7331 };
    112 	assert(s.y.a.b == 1337);
    113 	assert(s.y.a.c == 7331);
    114 };
    115 
    116 type coords = struct { x: int, y: int };
    117 
    118 type coords3 = struct { coords, z: int };
    119 type embed = struct { a: uint, b: u8 };
    120 // complex embedded hierarchy
    121 type me = struct { embed, coords3, f: int, g: (int, str) };
    122 let g1: me = me {        b = 4, x = -1, y = -2, z = -3, f = 20, ... };
    123 let g2: me = me {               x = -1, y = -2, z = -3, f = 20, ... };
    124 let g3: me = me {                       y = -2, z = -3, f = 20, ... };
    125 let g4: me = me {                               z = -3, f = 20, ... };
    126 let g5: me = me {                                       f = 20, ... };
    127 let g6: me = me {                                               ... };
    128 
    129 fn named() void = {
    130 	let x = coords { y = 10, x = 20 };
    131 	assert(x.x == 20 && x.y == 10);
    132 };
    133 
    134 fn autofill() void = {
    135 	let x = coords { x = 10, ... };
    136 	assert(x.x == 10 && x.y == 0);
    137 
    138 	assert(g1.a == 0 && g1.b == 4 && g1.x == -1 && g1.y == -2 && g1.z == -3 && g1.f == 20 && g1.g.0 == 0 && g1.g.1 == "");
    139 	assert(g2.a == 0 && g2.b == 0 && g2.x == -1 && g2.y == -2 && g2.z == -3 && g2.f == 20 && g2.g.0 == 0 && g2.g.1 == "");
    140 	assert(g3.a == 0 && g3.b == 0 && g3.x == 0  && g3.y == -2 && g3.z == -3 && g3.f == 20 && g3.g.0 == 0 && g3.g.1 == "");
    141 	assert(g4.a == 0 && g4.b == 0 && g4.x == 0  && g4.y == 0  && g4.z == -3 && g4.f == 20 && g4.g.0 == 0 && g4.g.1 == "");
    142 	assert(g5.a == 0 && g5.b == 0 && g5.x == 0  && g5.y == 0  && g5.z == 0  && g5.f == 20 && g5.g.0 == 0 && g5.g.1 == "");
    143 	assert(g6.a == 0 && g6.b == 0 && g6.x == 0  && g6.y == 0  && g6.z == 0  && g6.f == 0  && g6.g.0 == 0 && g6.g.1 == "");
    144 
    145 	let l1: me = me {        b = 4, x = -1, y = -2, z = -3, f = 20, ... };
    146 	let l2: me = me {               x = -1, y = -2, z = -3, f = 20, ... };
    147 	let l3: me = me {                       y = -2, z = -3, f = 20, ... };
    148 	let l4: me = me {                               z = -3, f = 20, ... };
    149 	let l5: me = me {                                       f = 20, ... };
    150 	let l6: me = me {                                               ... };
    151 
    152 	assert(l1.a == 0 && l1.b == 4 && l1.x == -1 && l1.y == -2 && l1.z == -3 && l1.f == 20 && l1.g.0 == 0 && l1.g.1 == "");
    153 	assert(l2.a == 0 && l2.b == 0 && l2.x == -1 && l2.y == -2 && l2.z == -3 && l2.f == 20 && l2.g.0 == 0 && l2.g.1 == "");
    154 	assert(l3.a == 0 && l3.b == 0 && l3.x == 0  && l3.y == -2 && l3.z == -3 && l3.f == 20 && l3.g.0 == 0 && l3.g.1 == "");
    155 	assert(l4.a == 0 && l4.b == 0 && l4.x == 0  && l4.y == 0  && l4.z == -3 && l4.f == 20 && l4.g.0 == 0 && l4.g.1 == "");
    156 	assert(l5.a == 0 && l5.b == 0 && l5.x == 0  && l5.y == 0  && l5.z == 0  && l5.f == 20 && l5.g.0 == 0 && l5.g.1 == "");
    157 	assert(l6.a == 0 && l6.b == 0 && l6.x == 0  && l6.y == 0  && l6.z == 0  && l6.f == 0  && l6.g.0 == 0 && l6.g.1 == "");
    158 };
    159 
    160 fn invariants() void = {
    161 	const failures = [
    162 	// Assign field from non-assignable type:
    163 	"fn test() void = { let x: struct { y: int } = struct { y: int = 10u }; };",
    164 
    165 	"
    166 	type coords = struct { x: int, y: int };
    167 
    168 	fn test() void = {
    169 		let x = coords { x: int = 10u, y: int = 20u };
    170 	};
    171 	",
    172 
    173 	// multiple initializations for single field
    174 	"type s = struct { x: int }; fn test() s = s { x = 5, x = 7 };",
    175 
    176 	"type e = struct { x: int }, s = struct { y: int, e };"
    177 	"fn test() s = s { x = 5, x = 7 };",
    178 
    179 	"type e = struct { x: int }, s = struct { e, y: int};"
    180 	"fn test() s = s { x = 5, x = 7 };",
    181 
    182 	// Duplicate members
    183 	"fn test() void = { let x: struct { a: int, a: int } = struct { a: int = 2 };"
    184 	// Dereference non-nullable pointer:
    185 	"fn test() void = { let x: nullable *struct { y: int } = null; x.y; };",
    186 	// Select field from non-struct object:
    187 	"fn test() void = { let x = 10; x.y; };",
    188 	// Unknown field:
    189 	"fn test() void = { let x: struct { y: int } = struct { y: int = 10 }; x.z; };",
    190 	// Untyped field for unnamed struct:
    191 	"fn test() void = { let x = struct { x = 10 }; };",
    192 	// Members of undefined size before last
    193 	"type s = struct { x: [*]int, a: str };",
    194 	// Members of size 0
    195 	"type s = struct { x: void, a: str };"
    196 	];
    197 	for (let i = 0z; i < len(failures); i += 1) {
    198 		assert(compile(failures[i]) as exited != EXIT_SUCCESS);
    199 	};
    200 };
    201 
    202 fn fields() void = {
    203 	let n: u32 = 0;
    204 
    205 	let up = &n: *union {
    206 		struct {
    207 			a: u8,
    208 			b: u8,
    209 		},
    210 		c: u32,
    211 	};
    212 	assert(&up.a: uintptr == &n: uintptr);
    213 	assert(&up.b: uintptr == &n: uintptr + 1);
    214 	assert(&up.c: uintptr == &n: uintptr);
    215 
    216 	let sp  = &n: *struct {
    217 		a: u8,
    218 		struct {
    219 			b: u8,
    220 			struct {
    221 				c: u8,
    222 			},
    223 		},
    224 	};
    225 	assert(&sp.a: uintptr == &n: uintptr);
    226 	assert(&sp.b: uintptr == &n: uintptr + 1);
    227 	assert(&sp.c: uintptr == &n: uintptr + 2);
    228 };
    229 
    230 def S = struct {
    231 	a: u8 = 69,
    232 	b: u32 = 1337,
    233 };
    234 
    235 fn eval() void = {
    236 	static let s = struct {
    237 		a: u8 = 69,
    238 		b: u32 = 1337,
    239 	};
    240 
    241 	static assert(S.a == 69);
    242 
    243 	static assert(struct {
    244 		a: u8 = 69,
    245 		b: u32 = 1337,
    246 	}.b == 1337);
    247 };
    248 
    249 export fn main() void = {
    250 	padding();
    251 	storage();
    252 	assignment();
    253 	deref();
    254 	nested();
    255 	named();
    256 	autofill();
    257 	invariants();
    258 	fields();
    259 	eval();
    260 	// TODO:
    261 	// - Union tests
    262 	// - Embedded structs
    263 	// - offset()
    264 };