hare

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

hash.ha (3970B)


      1 // License: MPL-2.0
      2 // (c) 2021 Drew DeVault <sir@cmpwn.com>
      3 // (c) 2021 Ember Sawady <ecs@d2evs.net>
      4 use endian;
      5 use hash::fnv;
      6 use hash;
      7 use strings;
      8 use fmt;
      9 
     10 // Keep ordered with respect to bootstrap harec:include/types.h
     11 type storage = enum u8 {
     12 	BOOL, F32, F64, I16, I32, I64, I8, INT, NULL, RUNE, SIZE, STRING,
     13 	U16, U32, U64, U8, UINT, UINTPTR, VOID, ALIAS, ARRAY, ENUM, FUNCTION,
     14 	POINTER, SLICE, STRUCT, TAGGED, TUPLE, UNION,
     15 };
     16 
     17 fn builtin_storage(b: builtin) u8 = {
     18 	switch (b) {
     19 	case builtin::BOOL =>
     20 		return storage::BOOL;
     21 	case builtin::F32 =>
     22 		return storage::F32;
     23 	case builtin::F64 =>
     24 		return storage::F64;
     25 	case builtin::I16 =>
     26 		return storage::I16;
     27 	case builtin::I32 =>
     28 		return storage::I32;
     29 	case builtin::I64 =>
     30 		return storage::I64;
     31 	case builtin::I8 =>
     32 		return storage::I8;
     33 	case builtin::INT =>
     34 		return storage::INT;
     35 	case builtin::NULL =>
     36 		return storage::NULL;
     37 	case builtin::RUNE =>
     38 		return storage::RUNE;
     39 	case builtin::SIZE =>
     40 		return storage::SIZE;
     41 	case builtin::STR =>
     42 		return storage::STRING;
     43 	case builtin::U16 =>
     44 		return storage::U16;
     45 	case builtin::U32 =>
     46 		return storage::U32;
     47 	case builtin::U64 =>
     48 		return storage::U64;
     49 	case builtin::U8 =>
     50 		return storage::U8;
     51 	case builtin::UINT =>
     52 		return storage::UINT;
     53 	case builtin::UINTPTR =>
     54 		return storage::UINTPTR;
     55 	case builtin::VOID =>
     56 		return storage::VOID;
     57 	};
     58 };
     59 
     60 fn type_storage(t: *_type) u8 = {
     61 	match (t.repr) {
     62 	case alias =>
     63 		return storage::ALIAS;
     64 	case array =>
     65 		return storage::ARRAY;
     66 	case let b: builtin =>
     67 		return builtin_storage(b);
     68 	case _enum =>
     69 		return storage::ENUM;
     70 	case func =>
     71 		return storage::FUNCTION;
     72 	case pointer =>
     73 		return storage::POINTER;
     74 	case slice =>
     75 		return storage::SLICE;
     76 	case let st: _struct =>
     77 		if (st.kind == struct_union::STRUCT) {
     78 			return storage::STRUCT;
     79 		} else {
     80 			return storage::UNION;
     81 		};
     82 	case tuple =>
     83 		return storage::TUPLE;
     84 	case tagged =>
     85 		return storage::TAGGED;
     86 	};
     87 };
     88 
     89 fn write8(h: *hash::hash, u: u8) void = {
     90 	let buf = &u: *[*]u8;
     91 	hash::write(h, buf[..1]);
     92 };
     93 
     94 fn write32(h: *hash::hash, u: u32) void = {
     95 	static let buf: [size(u32)]u8 = [0...];
     96 	endian::leputu32(buf, u);
     97 	hash::write(h, buf);
     98 };
     99 
    100 fn write64(h: *hash::hash, u: u64) void = {
    101 	static let buf: [size(u64)]u8 = [0...];
    102 	endian::leputu64(buf, u);
    103 	hash::write(h, buf);
    104 };
    105 
    106 // Returns the hash of a type. These hashes are deterministic and universally
    107 // unique: different computers will generate the same hash for the same type.
    108 export fn hash(t: *_type) u32 = {
    109 	// Note that this function should produce the same hashes as harec; see
    110 	// bootstrap harec:src/types.c:type_hash
    111 	let id = fnv::fnv32a();
    112 	write8(&id, type_storage(t));
    113 	write8(&id, t.flags);
    114 
    115 	match (t.repr) {
    116 	case let a: alias =>
    117 		for (let i = len(a.id); i > 0; i -= 1) {
    118 			hash::write(&id, strings::toutf8(a.id[i - 1]));
    119 			write8(&id, 0);
    120 		};
    121 	case let a: array =>
    122 		write32(&id, hash(a.member));
    123 		writesize(&id, a.length);
    124 	case builtin => void;
    125 	case let e: _enum =>
    126 		write8(&id, builtin_storage(e.storage));
    127 		for (let i = 0z; i < len(e.values); i += 1) {
    128 			hash::write(&id, strings::toutf8(e.values[i].0));
    129 			write64(&id, e.values[i].1);
    130 		};
    131 	case let f: func =>
    132 		write32(&id, hash(f.result));
    133 		write8(&id, f.variadism: u8);
    134 		write8(&id, f.flags: u8);
    135 		for (let i = 0z; i < len(f.params); i += 1) {
    136 			write32(&id, hash(f.params[i]));
    137 		};
    138 	case let p: pointer =>
    139 		write8(&id, p.flags);
    140 		write32(&id, hash(p.referent));
    141 	case let s: slice =>
    142 		write32(&id, hash(s));
    143 	case let st: _struct =>
    144 		for (let i = 0z; i < len(st.fields); i += 1) {
    145 			const field = st.fields[i];
    146 			hash::write(&id, strings::toutf8(field.name));
    147 			write32(&id, hash(field._type));
    148 			writesize(&id, field.offs);
    149 		};
    150 	case let tu: tuple =>
    151 		for (let i = 0z; i < len(tu); i += 1) {
    152 			write32(&id, hash(tu[i]._type));
    153 		};
    154 	case let ta: tagged =>
    155 		for (let i = 0z; i < len(ta); i += 1) {
    156 			write32(&id, hash(ta[i]));
    157 		};
    158 	};
    159 
    160 	return fnv::sum32(&id);
    161 };