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