harec

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

15-enums.ha (4210B)


      1 use rt::{compile, exited, EXIT_SUCCESS};
      2 use testmod;
      3 
      4 type implicit_values = enum {
      5 	ZERO,
      6 	ONE,
      7 	TWO,
      8 };
      9 
     10 fn implicit() void = {
     11 	assert(implicit_values::ZERO == 0);
     12 	assert(implicit_values::ONE == 1);
     13 	assert(implicit_values::TWO == 2);
     14 };
     15 
     16 type explicit_values = enum {
     17 	NEGONE = -1,
     18 	SIXTEEN = 16,
     19 	SEVENTEEN,
     20 	EIGHTEEN,
     21 	FIFTY = 50,
     22 };
     23 
     24 fn explicit() void = {
     25 	assert(explicit_values::NEGONE == -1);
     26 	assert(explicit_values::SIXTEEN == 16);
     27 	assert(explicit_values::SEVENTEEN == 17);
     28 	assert(explicit_values::EIGHTEEN == 18);
     29 	assert(explicit_values::FIFTY == 50);
     30 };
     31 
     32 type with_storage = enum u16 {
     33 	CAFE = 0xCAFE,
     34 	BABE = 0xBABE,
     35 	DEAD = 0xDEAD,
     36 	BEEF = 0xBEEF,
     37 };
     38 
     39 type char_storage = enum char {
     40 	FOO = 0,
     41 	BAR = 1,
     42 };
     43 
     44 type rune_storage = enum rune {
     45 	FOO = '0',
     46 	BAR = '1',
     47 };
     48 
     49 type uintptr_storage = enum uintptr {
     50 	FOO = 0,
     51 	BAR = 1,
     52 };
     53 
     54 let global_uintptr: uintptr_storage = uintptr_storage::FOO;
     55 
     56 fn storage() void = {
     57 	assert(size(explicit_values) == size(int));
     58 	assert(size(with_storage) == size(u16));
     59 	assert(size(uintptr_storage) == size(uintptr));
     60 	assert(align(explicit_values) == align(int));
     61 	assert(align(with_storage) == align(u16));
     62 	assert(align(uintptr_storage) == align(uintptr));
     63 
     64 	const val = 0xBEEFu16;
     65 	const is_little = (&val: *[2]u8)[0] == 0xEF;
     66 	assert(with_storage::CAFE: u8 == (if (is_little) 0xFEu8 else 0xCAu8));
     67 	assert(with_storage::BABE: u8 == (if (is_little) 0xBEu8 else 0xBAu8));
     68 	assert(with_storage::DEAD: u8 == (if (is_little) 0xADu8 else 0xDEu8));
     69 	assert(with_storage::BEEF: u8 == (if (is_little) 0xEFu8 else 0xBEu8));
     70 	assert(char_storage::FOO == 0 && char_storage::BAR == 1);
     71 	assert(rune_storage::FOO == '0' && rune_storage::BAR == '1');
     72 };
     73 
     74 fn reject() void = {
     75 	// enum type definition used outside type declaration
     76 	assert(compile("export let a: enum { A, B } = 0;") as exited != EXIT_SUCCESS);
     77 	assert(compile("export let a: int = 0: enum{A, B}: int;") as exited != EXIT_SUCCESS);
     78 
     79 	// enum circular dependencies
     80 	assert(compile("type a = enum { A = B, B = A };") as exited != EXIT_SUCCESS);
     81 	assert(compile("type a = enum { A = b::B },
     82 				b = enum { B = a::A };") as exited != EXIT_SUCCESS);
     83 	assert(compile("
     84 		def a: int = e::VAL1;
     85 		type e = enum { VAL1 = a };
     86 	") as exited != EXIT_SUCCESS);
     87 	assert(compile("
     88 		def a: int = e::VAL1;
     89 		type e = enum { VAL1 = VAL2, VAL2 = a };
     90 	") as exited != EXIT_SUCCESS);
     91 };
     92 
     93 type interdependent1 = enum {
     94 	A = 0,
     95 	B = interdependent2::A + 1,
     96 	C = interdependent2::B + 1,
     97 };
     98 
     99 type interdependent2 = enum {
    100 	A = interdependent1::A + 1,
    101 	B = interdependent1::B + 1,
    102 	C = interdependent1::C + 1,
    103 };
    104 
    105 fn interdependent() void = {
    106 	assert(interdependent1::A == 0);
    107 	assert(interdependent2::A == 1);
    108 	assert(interdependent1::B == 2);
    109 	assert(interdependent2::B == 3);
    110 	assert(interdependent1::C == 4);
    111 	assert(interdependent2::C == 5);
    112 };
    113 
    114 type e1 = enum { a, b, c, d }, a1 = e1;
    115 type a2 = e2, e2 = enum u8 { a, b, c, d }; // reverse
    116 
    117 type imported_alias = testmod::_enum;
    118 
    119 type imported_double_alias = testmod::enum_alias;
    120 
    121 fn aliases() void = {
    122 	assert(size(a1) == size(e1));
    123 	assert(a1::a == e1::a);
    124 	assert(a1::b == e1::b);
    125 	assert(a1::c == e1::c);
    126 	assert(a1::d == e1::d);
    127 
    128 	assert(size(a2) == size(e2));
    129 	assert(a2::a == e2::a);
    130 	assert(a2::b == e2::b);
    131 	assert(a2::c == e2::c);
    132 	assert(a2::d == e2::d);
    133 
    134 	// test with alias of imported enum
    135 	assert(imported_alias::ONE == testmod::_enum::ONE);
    136 	assert(imported_alias::TWO == testmod::_enum::TWO);
    137 	assert(imported_alias::THREE == testmod::_enum::THREE);
    138 
    139 	assert(imported_double_alias::ONE == testmod::_enum::ONE);
    140 	assert(imported_double_alias::TWO == testmod::_enum::TWO);
    141 	assert(imported_double_alias::THREE == testmod::_enum::THREE);
    142 };
    143 
    144 // Force T2 to be resolved before t2::T3 and t2::T3 before t2::T1
    145 type t1 = enum {
    146 	I1 = t2::T1,
    147 	I2 = t2::T3,
    148 	I3 = T2: int,
    149 };
    150 
    151 def T2: uint = 0;
    152 
    153 type t2 = enum {
    154 	T1,
    155 	T2 = 1,
    156 	T3 = T2 + 1,
    157 };
    158 
    159 fn resolution_order() void = {
    160 	assert(t2::T1 == 0);
    161 	assert(t2::T2 == 1);
    162 	assert(t2::T3 == 2);
    163 	assert(t1::I1 == 0);
    164 	assert(t1::I2 == 2);
    165 	assert(t1::I3 == 0);
    166 	assert(T2 == 0);
    167 };
    168 
    169 export fn main() void = {
    170 	implicit();
    171 	explicit();
    172 	storage();
    173 	reject();
    174 	interdependent();
    175 	aliases();
    176 	resolution_order();
    177 };