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 };