+test.ha (10849B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use bufio; 5 use fmt; 6 use hare::ast; 7 use hare::lex; 8 use hare::parse; 9 use io; 10 use memio; 11 use strings; 12 use types; 13 14 fn parse_type(in: str) ast::_type = { 15 let buf = memio::fixed(strings::toutf8(in)); 16 let sc = bufio::newscanner(&buf); 17 defer bufio::finish(&sc); 18 let lex = lex::init(&sc, "<test>"); 19 return parse::_type(&lex)!; 20 }; 21 22 @test fn store() void = { 23 let st = store(x86_64, null, null); 24 defer store_free(st); 25 26 let atype = parse_type("int"); 27 defer ast::type_finish(&atype); 28 let htype = lookup(st, &atype)!; 29 assert(htype.repr as builtin == builtin::INT); 30 assert(htype.sz == x86_64._int && htype._align == x86_64._int); 31 32 let type2 = lookup(st, &atype)!; 33 assert(htype == type2, "types should be singletons"); 34 35 let atype = parse_type("*int"); 36 defer ast::type_finish(&atype); 37 let htype = lookup(st, &atype)!; 38 assert(htype.sz == x86_64._pointer && htype._align == x86_64._pointer); 39 let htype = htype.repr as pointer; 40 assert(htype.referent.repr as builtin == builtin::INT); 41 }; 42 43 fn resolve( 44 rstate: nullable *opaque, 45 store: *typestore, 46 expr: const *ast::expr, 47 ) (size | deferred | error) = { 48 let expr = expr.expr as ast::literal_expr; 49 let n = expr as ast::number_literal; 50 let ival = n.value as i64; 51 assert(ival >= 0); 52 return ival: size; 53 }; 54 55 @test fn structs() void = { 56 let st = store(x86_64, &resolve, null); 57 defer store_free(st); 58 59 // Basic struct 60 let atype = parse_type("struct { x: int, y: int }"); 61 defer ast::type_finish(&atype); 62 let htype = lookup(st, &atype)!; 63 assert(htype.sz == 8); 64 assert(htype._align == 4); 65 let stype = htype.repr as _struct; 66 assert(stype.kind == struct_union::STRUCT); 67 assert(len(stype.fields) == 2); 68 69 let x = stype.fields[0]; 70 assert(x.name == "x"); 71 assert(x.offs == 0); 72 assert(x._type.repr as builtin == builtin::INT); 73 74 let y = stype.fields[1]; 75 assert(y.name == "y"); 76 assert(y.offs == 4); 77 assert(y._type.repr as builtin == builtin::INT); 78 79 // Basic union 80 let atype = parse_type("union { x: int, y: int }"); 81 defer ast::type_finish(&atype); 82 let htype = lookup(st, &atype)!; 83 assert(htype.sz == 4); 84 assert(htype._align == 4); 85 let stype = htype.repr as _struct; 86 assert(stype.kind == struct_union::UNION); 87 assert(len(stype.fields) == 2); 88 89 let x = stype.fields[0]; 90 assert(x.name == "x"); 91 assert(x.offs == 0); 92 assert(x._type.repr as builtin == builtin::INT); 93 94 let y = stype.fields[1]; 95 assert(y.name == "y"); 96 assert(y.offs == 0); 97 assert(y._type.repr as builtin == builtin::INT); 98 99 // Padding 100 let atype = parse_type("struct { w: u8, x: u32, y: u8, z: u64 }"); 101 defer ast::type_finish(&atype); 102 let htype = lookup(st, &atype)!; 103 assert(htype.sz == 24); 104 assert(htype._align == 8); 105 let stype = htype.repr as _struct; 106 assert(stype.kind == struct_union::STRUCT); 107 108 let w = stype.fields[0]; 109 assert(w.offs == 0); 110 let x = stype.fields[1]; 111 assert(x.offs == 4); 112 let y = stype.fields[2]; 113 assert(y.offs == 8); 114 let z = stype.fields[3]; 115 assert(z.offs == 16); 116 117 let atype = parse_type("struct { x: u8, y: size, z: u8 }"); 118 defer ast::type_finish(&atype); 119 let htype = lookup(st, &atype)!; 120 assert(htype.sz == 24); 121 122 // Sort order 123 let atype = parse_type("struct { z: u8, y: u8, x: u8, q: u8 }"); 124 defer ast::type_finish(&atype); 125 let htype = lookup(st, &atype)!; 126 let stype = htype.repr as _struct; 127 assert(stype.fields[0].name == "q"); 128 assert(stype.fields[1].name == "x"); 129 assert(stype.fields[2].name == "y"); 130 assert(stype.fields[3].name == "z"); 131 132 // Embedded struct 133 let atype = parse_type("struct { 134 x: int, 135 y: int, 136 struct { 137 z: int, 138 q: int, 139 }, 140 p: int, 141 }"); 142 defer ast::type_finish(&atype); 143 let htype = lookup(st, &atype)!; 144 assert(htype.sz == 20); 145 assert(htype._align == 4); 146 let stype = htype.repr as _struct; 147 assert(stype.fields[0].name == "p"); 148 assert(stype.fields[0].offs == 16); 149 assert(stype.fields[1].name == "q"); 150 assert(stype.fields[1].offs == 12); 151 assert(stype.fields[2].name == "x"); 152 assert(stype.fields[2].offs == 0); 153 assert(stype.fields[3].name == "y"); 154 assert(stype.fields[3].offs == 4); 155 assert(stype.fields[4].name == "z"); 156 assert(stype.fields[4].offs == 8); 157 158 // Embedded union 159 let atype = parse_type("struct { 160 x: int, 161 y: int, 162 union { 163 z: int, 164 q: int, 165 }, 166 p: int, 167 }"); 168 defer ast::type_finish(&atype); 169 let htype = lookup(st, &atype)!; 170 assert(htype.sz == 16); 171 assert(htype._align == 4); 172 let stype = htype.repr as _struct; 173 assert(stype.fields[0].name == "p"); 174 assert(stype.fields[0].offs == 12); 175 assert(stype.fields[1].name == "q"); 176 assert(stype.fields[1].offs == 8); 177 assert(stype.fields[2].name == "x"); 178 assert(stype.fields[2].offs == 0); 179 assert(stype.fields[3].name == "y"); 180 assert(stype.fields[3].offs == 4); 181 assert(stype.fields[4].name == "z"); 182 assert(stype.fields[4].offs == 8); 183 184 // Embedded (struct) alias 185 // TODO 186 187 // Embedded (union) alias 188 // TODO 189 190 // Explicit offsets 191 let atype = parse_type("struct { 192 @offset(8) x: int, 193 @offset(16) y: int, 194 @offset(32) z: int, 195 }"); 196 defer ast::type_finish(&atype); 197 let htype = lookup(st, &atype)!; 198 assert(htype.sz == 36); 199 assert(htype._align == 4); 200 let stype = htype.repr as _struct; 201 assert(stype.fields[0].name == "x"); 202 assert(stype.fields[0].offs == 8); 203 assert(stype.fields[1].name == "y"); 204 assert(stype.fields[1].offs == 16); 205 assert(stype.fields[2].name == "z"); 206 assert(stype.fields[2].offs == 32); 207 }; 208 209 @test fn tuples() void = { 210 let st = store(x86_64, &resolve, null); 211 defer store_free(st); 212 213 // Basic case 214 let atype = parse_type("(int, int)"); 215 defer ast::type_finish(&atype); 216 let htype = lookup(st, &atype)!; 217 assert(htype.sz == 8); 218 assert(htype._align == 4); 219 let tup = htype.repr as tuple; 220 assert(len(tup) == 2); 221 222 assert(tup[0].offs == 0); 223 assert(tup[0]._type.repr as builtin == builtin::INT); 224 assert(tup[1].offs == 4); 225 assert(tup[1]._type.repr as builtin == builtin::INT); 226 227 // Padding 228 let atype = parse_type("(i8, i32, i8, i64)"); 229 defer ast::type_finish(&atype); 230 let htype = lookup(st, &atype)!; 231 assert(htype.sz == 24); 232 assert(htype._align == 8); 233 234 let tup = htype.repr as tuple; 235 assert(tup[0].offs == 0); 236 assert(tup[1].offs == 4); 237 assert(tup[2].offs == 8); 238 assert(tup[3].offs == 16); 239 }; 240 241 @test fn lists() void = { 242 let st = store(x86_64, &resolve, null); 243 defer store_free(st); 244 245 // Slice 246 let atype = parse_type("[]int"); 247 defer ast::type_finish(&atype); 248 let htype = lookup(st, &atype)!; 249 assert(htype.sz == 24); 250 assert(htype._align == 8); 251 let slice = htype.repr as slice; 252 assert(slice.repr as builtin == builtin::INT); 253 254 // Normal array 255 let atype = parse_type("[5]i32"); 256 defer ast::type_finish(&atype); 257 let htype = lookup(st, &atype)!; 258 assert(htype.sz == 4 * 5); 259 assert(htype._align == 4); 260 let arr = htype.repr as array; 261 assert(arr.member.repr as builtin == builtin::I32); 262 assert(arr.length == 5); 263 264 // Unbounded array 265 let atype = parse_type("[*]i32"); 266 defer ast::type_finish(&atype); 267 let htype = lookup(st, &atype)!; 268 assert(htype.sz == SIZE_UNDEFINED); 269 assert(htype._align == 4); 270 let arr = htype.repr as array; 271 assert(arr.member.repr as builtin == builtin::I32); 272 assert(arr.length == SIZE_UNDEFINED); 273 274 // Contextual array (equivalent to unbounded at this compilation stage) 275 let atype = parse_type("[_]i32"); 276 defer ast::type_finish(&atype); 277 let htype = lookup(st, &atype)!; 278 assert(htype.sz == SIZE_UNDEFINED); 279 assert(htype._align == 4); 280 let arr = htype.repr as array; 281 assert(arr.member.repr as builtin == builtin::I32); 282 assert(arr.length == SIZE_UNDEFINED); 283 }; 284 285 @test fn funcs() void = { 286 let st = store(x86_64, &resolve, null); 287 defer store_free(st); 288 289 let atype = parse_type("fn() never"); 290 defer ast::type_finish(&atype); 291 let htype = lookup(st, &atype)!; 292 assert(htype.sz == SIZE_UNDEFINED); 293 assert(htype._align == SIZE_UNDEFINED); 294 let f = htype.repr as func; 295 assert(f.result.repr as builtin == builtin::NEVER); 296 assert(f.variadism == variadism::NONE); 297 assert(len(f.params) == 0); 298 299 let atype = parse_type("fn(foo: int, bar: str...) int"); 300 defer ast::type_finish(&atype); 301 let htype = lookup(st, &atype)!; 302 assert(htype.sz == SIZE_UNDEFINED); 303 assert(htype._align == SIZE_UNDEFINED); 304 let f = htype.repr as func; 305 assert(f.result.repr as builtin == builtin::INT); 306 assert(f.variadism == variadism::HARE); 307 assert(len(f.params) == 2); 308 assert(f.params[0].repr as builtin == builtin::INT); 309 assert(f.params[1].repr as builtin == builtin::STR); 310 }; 311 312 @test fn tagged() void = { 313 let st = store(x86_64, &resolve, null); 314 defer store_free(st); 315 316 let atype = parse_type("(int | int | void)"); 317 defer ast::type_finish(&atype); 318 let htype = lookup(st, &atype)!; 319 assert(htype.sz == st.arch._int * 2); 320 assert(htype._align == st.arch._int); 321 let t = htype.repr as tagged; 322 assert(len(t) == 2); 323 assert(t[0].repr as builtin == builtin::INT); 324 assert(t[1].repr as builtin == builtin::VOID); 325 326 let atype = parse_type("(int | (int | str | void))"); 327 defer ast::type_finish(&atype); 328 let htype = lookup(st, &atype)!; 329 assert(htype.sz == 32); 330 assert(htype._align == 8); 331 let t = htype.repr as tagged; 332 assert(len(t) == 3); 333 assert(t[0].repr as builtin == builtin::INT); 334 assert(t[1].repr as builtin == builtin::VOID); 335 assert(t[2].repr as builtin == builtin::STR); 336 }; 337 338 @test fn alias() void = { 339 let st = store(x86_64, &resolve, null); 340 defer store_free(st); 341 342 const of = lookup_builtin(st, ast::builtin_type::U64); 343 const al = newalias(st, ["myalias"], of); 344 assert(al.sz == 8); 345 assert(al._align == 8); 346 assert(al.flags == 0); 347 assert((al.repr as alias).secondary == of); 348 349 const atype = parse_type("myalias"); 350 defer ast::type_finish(&atype); 351 const htype = lookup(st, &atype)!; 352 assert(htype == al); 353 }; 354 355 @test fn forwardref() void = { 356 let st = store(x86_64, &resolve, null); 357 defer store_free(st); 358 359 const atype = parse_type("myalias"); 360 defer ast::type_finish(&atype); 361 const htype = lookup(st, &atype)!; 362 assert((htype.repr as alias).secondary == null); 363 364 const of = lookup_builtin(st, ast::builtin_type::U64); 365 const al = newalias(st, ["myalias"], of); 366 assert(htype.sz == 8); 367 assert(htype._align == 8); 368 assert(htype.flags == 0); 369 assert((htype.repr as alias).secondary == of); 370 }; 371 372 @test fn builtins() void = { 373 const builtins = [ 374 (&builtin_bool, "bool"), 375 (&builtin_done, "done"), 376 (&builtin_f32, "f32"), 377 (&builtin_f64, "f64"), 378 (&builtin_i8, "i8"), 379 (&builtin_i16, "i16"), 380 (&builtin_i32, "i32"), 381 (&builtin_i64, "i64"), 382 (&builtin_opaque, "opaque"), 383 (&builtin_rune, "rune"), 384 (&builtin_u8, "u8"), 385 (&builtin_u16, "u16"), 386 (&builtin_u32, "u32"), 387 (&builtin_u64, "u64"), 388 (&builtin_void, "void"), 389 ]; 390 for (let i = 0z; i < len(builtins); i += 1) { 391 const expected = hash(builtins[i].0); 392 const actual = builtins[i].0.id; 393 if (expected != actual) { 394 fmt::errorfln("expected type {} to have ID {}, but got {}", 395 builtins[i].1, expected, actual)!; 396 abort(); 397 }; 398 }; 399 };