hare

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

commit 96ced5c8c0e9619026e0c9343a257584a6d18230
parent c5b4c37c373d7a891c1b743da6408906b141f701
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu, 29 Apr 2021 09:32:22 -0400

hare::types: initial pass for new module

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mhare/ast/ident.ha | 11+++++++++++
Ahare/types/hash.ha | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahare/types/store.ha | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahare/types/types.ha | 25+++++++++++++++++++++++++
Mscripts/gen-stdlib | 11++++++++++-
Mstdlib.mk | 34++++++++++++++++++++++++++++++++--
6 files changed, 205 insertions(+), 3 deletions(-)

diff --git a/hare/ast/ident.ha b/hare/ast/ident.ha @@ -1,3 +1,5 @@ +use strings; + // Identifies a single object, e.g. foo::bar::baz. export type ident = []str; @@ -27,3 +29,12 @@ export fn ident_eq(a: ident, b: ident) bool = { }; return true; }; + +// Duplicates an [[ident]]. +export fn ident_dup(id: ident) ident = { + let new: ident = alloc([], len(id)); + for (let i = 0z; i < len(id); i += 1) { + append(new, strings::dup(id[0])); + }; + return new; +}; diff --git a/hare/types/hash.ha b/hare/types/hash.ha @@ -0,0 +1,75 @@ +use endian; +use hash::fnv; +use hash; +use strings; +use fmt; + +// Keep ordered with respect to bootstrap harec:include/types.h +type storage = enum u8 { + BOOL, CHAR, ENUM, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, + NULL, RUNE, SIZE, U16, U32, U64, U8, UINT, UINTPTR, VOID, ALIAS, ARRAY, + FUNCTION, POINTER, SLICE, STRING, STRUCT, TAGGED, TUPLE, UNION, +}; + +fn type_storage(t: *_type) u8 = match (t._type) { + alias => storage::ALIAS, + t: builtin => switch (t) { + builtin::BOOL => storage::BOOL, + builtin::CHAR => storage::CHAR, + builtin::F32 => storage::F32, + builtin::F64 => storage::F64, + builtin::I16 => storage::I16, + builtin::I32 => storage::I32, + builtin::I64 => storage::I64, + builtin::I8 => storage::I8, + builtin::INT => storage::INT, + builtin::NULL => storage::NULL, + builtin::RUNE => storage::RUNE, + builtin::SIZE => storage::SIZE, + builtin::STR => storage::STRING, + builtin::U16 => storage::U16, + builtin::U32 => storage::U32, + builtin::U64 => storage::U64, + builtin::U8 => storage::U8, + builtin::UINT => storage::UINT, + builtin::UINTPTR => storage::UINTPTR, + builtin::VOID => storage::VOID, + }, + * => abort(), // TODO +}; + +fn write8(h: *hash::hash, u: u8) void = { + let buf = &u: *[*]u8; + hash::write(h, buf[..1]); +}; + +// Returns the hash of a type. These hashes are deterministic and universally +// unique: different computers will generate the same hash for the same type. +export fn hash(t: *_type) u32 = { + let hash = fnv::fnv32a(); + defer hash::close(hash); + write8(hash, type_storage(t)); + write8(hash, t.flags); + + match (t._type) { + a: alias => for (let i = 0z; i < len(a); i += 1) { + hash::write(hash, strings::toutf8(a[i])); + write8(hash, 0); + }, + builtin => void, + }; + + return fnv::sum32(hash); +}; + +@test fn hash() void = { + // Test a few samples for ABI compatibility with harec + let sample = _type { + flags = flags::NONE, + _type = builtin::STR, + }; + fmt::errorfln("{}", hash(&sample))!; + assert(hash(&sample) == 3350498318); + + // TODO: more samples +}; diff --git a/hare/types/store.ha b/hare/types/store.ha @@ -0,0 +1,52 @@ +use hare::ast; + +export def BUCKETS: size = 65535; + +// A type store. Holds singletons for types in a hash map. +export type typestore = struct { + map: [BUCKETS][]struct { + hash: u32, + _type: _type, + }, +}; + +// Initializes a new type store. +export fn store() *typestore = alloc(typestore { ... }); + +// Retrieves a [[_type]] for a given [[ast::_type]]. +export fn lookup(store: *typestore, t: *ast::_type) const *_type = { + const t = fromast(t); + const h = hash(&t); + let bucket = &store.map[h % BUCKETS]; + // XXX: Should not have to dereference bucket + for (let i = 0z; i < len(*bucket); i += 1) { + if (bucket[i].hash == h) { + type_finish(&t); + return &bucket[i]._type; + }; + }; + append(*bucket, struct { + hash: u32 = h, + _type: _type = t, + }); + return &bucket[len(*bucket) - 1]._type; +}; + +fn fromast(atype: *ast::_type) _type = { + let underlying = match (atype._type) { + a: ast::alias_type => { + assert(!a.unwrap); // TODO + ast::ident_dup(a.ident): alias; + }, + b: ast::builtin_type => b: builtin, + * => abort(), // TODO + }; + return _type { + flags = atype.flags: flags, + _type = underlying, + }; +}; + +fn type_finish(t: *_type) void = { + void; // TODO +}; diff --git a/hare/types/types.ha b/hare/types/types.ha @@ -0,0 +1,25 @@ +use hare::ast; + +// A type alias. +export type alias = ast::ident; + +// A built-in primitive type (int, bool, str, etc). +export type builtin = enum u8 { + // Keep me consistent with ast::builtin + BOOL, CHAR, F32, F64, I16, I32, I64, I8, INT, NULL, RUNE, SIZE, STR, + U16, U32, U64, U8, UINT, UINTPTR, VOID, +}; + +// Flags for a Hare type. +export type flags = enum u8 { + NONE = 0, + // Keep me consistent with ast::type_flags + CONST = 1 << 0, + ERROR = 1 << 1, +}; + +// A Hare type. +export type _type = struct { + flags: flags, + _type: (alias | builtin), +}; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -355,7 +355,15 @@ hare_ast() { import.ha \ type.ha \ unit.ha - gen_ssa hare::ast hare::lex + gen_ssa hare::ast hare::lex strings +} + +hare_types() { + gen_srcs hare::types \ + hash.ha \ + store.ha \ + types.ha + gen_ssa hare::types hare::ast hash hash::fnv endian } hare_unparse() { @@ -733,6 +741,7 @@ hare_ast hare_lex hare_module hare_parse +hare_types hare_unparse hash hash_adler32 diff --git a/stdlib.mk b/stdlib.mk @@ -161,6 +161,9 @@ hare_stdlib_deps+=$(stdlib_hare_module) stdlib_hare_parse=$(HARECACHE)/hare/parse/hare_parse.o hare_stdlib_deps+=$(stdlib_hare_parse) +stdlib_hare_types=$(HARECACHE)/hare/types/hare_types.o +hare_stdlib_deps+=$(stdlib_hare_types) + stdlib_hare_unparse=$(HARECACHE)/hare/unparse/hare_unparse.o hare_stdlib_deps+=$(stdlib_hare_unparse) @@ -524,7 +527,7 @@ stdlib_hare_ast_srcs= \ $(STDLIB)/hare/ast/type.ha \ $(STDLIB)/hare/ast/unit.ha -$(HARECACHE)/hare/ast/hare_ast.ssa: $(stdlib_hare_ast_srcs) $(stdlib_rt) $(stdlib_hare_lex) +$(HARECACHE)/hare/ast/hare_ast.ssa: $(stdlib_hare_ast_srcs) $(stdlib_rt) $(stdlib_hare_lex) $(stdlib_strings) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/hare/ast @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::ast \ @@ -570,6 +573,18 @@ $(HARECACHE)/hare/parse/hare_parse.ssa: $(stdlib_hare_parse_srcs) $(stdlib_rt) $ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::parse \ -t$(HARECACHE)/hare/parse/hare_parse.td $(stdlib_hare_parse_srcs) +# hare::types +stdlib_hare_types_srcs= \ + $(STDLIB)/hare/types/hash.ha \ + $(STDLIB)/hare/types/store.ha \ + $(STDLIB)/hare/types/types.ha + +$(HARECACHE)/hare/types/hare_types.ssa: $(stdlib_hare_types_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hash) $(stdlib_hash_fnv) $(stdlib_endian) + @printf 'HAREC \t$@\n' + @mkdir -p $(HARECACHE)/hare/types + @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::types \ + -t$(HARECACHE)/hare/types/hare_types.td $(stdlib_hare_types_srcs) + # hare::unparse stdlib_hare_unparse_srcs= \ $(STDLIB)/hare/unparse/expr.ha \ @@ -1088,6 +1103,9 @@ hare_testlib_deps+=$(testlib_hare_module) testlib_hare_parse=$(TESTCACHE)/hare/parse/hare_parse.o hare_testlib_deps+=$(testlib_hare_parse) +testlib_hare_types=$(TESTCACHE)/hare/types/hare_types.o +hare_testlib_deps+=$(testlib_hare_types) + testlib_hare_unparse=$(TESTCACHE)/hare/unparse/hare_unparse.o hare_testlib_deps+=$(testlib_hare_unparse) @@ -1460,7 +1478,7 @@ testlib_hare_ast_srcs= \ $(STDLIB)/hare/ast/type.ha \ $(STDLIB)/hare/ast/unit.ha -$(TESTCACHE)/hare/ast/hare_ast.ssa: $(testlib_hare_ast_srcs) $(testlib_rt) $(testlib_hare_lex) +$(TESTCACHE)/hare/ast/hare_ast.ssa: $(testlib_hare_ast_srcs) $(testlib_rt) $(testlib_hare_lex) $(testlib_strings) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/hare/ast @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::ast \ @@ -1512,6 +1530,18 @@ $(TESTCACHE)/hare/parse/hare_parse.ssa: $(testlib_hare_parse_srcs) $(testlib_rt) @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::parse \ -t$(TESTCACHE)/hare/parse/hare_parse.td $(testlib_hare_parse_srcs) +# hare::types +testlib_hare_types_srcs= \ + $(STDLIB)/hare/types/hash.ha \ + $(STDLIB)/hare/types/store.ha \ + $(STDLIB)/hare/types/types.ha + +$(TESTCACHE)/hare/types/hare_types.ssa: $(testlib_hare_types_srcs) $(testlib_rt) $(testlib_hare_ast) $(testlib_hash) $(testlib_hash_fnv) $(testlib_endian) + @printf 'HAREC \t$@\n' + @mkdir -p $(TESTCACHE)/hare/types + @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::types \ + -t$(TESTCACHE)/hare/types/hare_types.td $(testlib_hare_types_srcs) + # hare::unparse testlib_hare_unparse_srcs= \ $(STDLIB)/hare/unparse/expr.ha \