hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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