hare

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

commit b418d70857bd7262362b1a48f72f47f79622c03e
parent c475996982ec81275b76cb8b20386aa234cb9f94
Author: Sebastian <sebastian@sebsite.pw>
Date:   Wed, 30 Aug 2023 20:25:46 -0400

hare::*: add never and remove @noreturn

Signed-off-by: Sebastian <sebastian@sebsite.pw>

Diffstat:
Mcmd/harec/gen.ha | 1-
Mcmd/haredoc/hare.ha | 3---
Mcmd/haredoc/html.ha | 7-------
Mcmd/haredoc/tty.ha | 9---------
Mhare/ast/type.ha | 12+++---------
Mhare/lex/token.ha | 4++--
Mhare/parse/+test/loc.ha | 2+-
Mhare/parse/decl.ha | 9++-------
Mhare/parse/type.ha | 14++++----------
Mhare/types/+test.ha | 14++++++--------
Mhare/types/builtins.ha | 22+++++++++++++++-------
Mhare/types/hash.ha | 5+++--
Mhare/types/store.ha | 8++++----
Mhare/types/types.ha | 12+++---------
Mhare/unparse/decl.ha | 7+------
Mhare/unparse/type.ha | 10+++-------
16 files changed, 47 insertions(+), 92 deletions(-)

diff --git a/cmd/harec/gen.ha b/cmd/harec/gen.ha @@ -49,7 +49,6 @@ fn gen_func(ctx: *context, decl: *unit::decl) void = { return; // Prototype }; const fntype = fndecl.prototype.repr as types::func; - assert(fntype.flags == 0); ctx.serial = 0; const ident = module::identuscore(fndecl.ident); diff --git a/cmd/haredoc/hare.ha b/cmd/haredoc/hare.ha @@ -183,9 +183,6 @@ fn unparse_hare(out: io::handle, d: ast::decl) (size | io::error) = { yield "@test "; })?; let p = f.prototype.repr as ast::func_type; - if (p.attrs & ast::func_attrs::NORETURN != 0) { - n += fmt::fprint(out, "@noreturn ")?; - }; if (len(f.symbol) != 0) { n += fmt::fprintf(out, "@symbol(\"{}\") ", f.symbol)?; diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha @@ -501,9 +501,6 @@ fn unparse_html(out: io::handle, d: ast::decl) (size | io::error) = { yield "@test "; })?; let p = f.prototype.repr as ast::func_type; - if (p.attrs & ast::func_attrs::NORETURN != 0) { - n += fmt::fprint(out, "@noreturn ")?; - }; n += fmt::fprint(out, "<span class='keyword'>fn</span> ")?; n += unparse::ident(out, f.ident)?; n += prototype_html(out, 0, @@ -718,10 +715,6 @@ fn type_html( z += fmt::fprint(out, "*")?; z += type_html(out, indent, *t.referent, brief)?; case let t: ast::func_type => - if (t.attrs & ast::func_attrs::NORETURN == ast::func_attrs::NORETURN) { - z += fmt::fprint(out, "@noreturn ")?; - }; - z += fmt::fprint(out, "<span class='keyword'>fn</span>(")?; for (let i = 0z; i < len(t.params); i += 1) { const param = t.params[i]; diff --git a/cmd/haredoc/tty.ha b/cmd/haredoc/tty.ha @@ -222,11 +222,6 @@ fn unparse_tty(out: io::handle, d: ast::decl) (size | io::error) = { n += render(out, syn::NORMAL)?; let p = f.prototype.repr as ast::func_type; - if (p.attrs & ast::func_attrs::NORETURN != 0) { - n += render(out, syn::ATTRIBUTE)?; - n += fmt::fprint(out, "@noreturn ")?; - n += render(out, syn::NORMAL)?; - }; if (len(f.symbol) != 0) { n += render(out, syn::ATTRIBUTE)?; n += fmt::fprintf(out, "@symbol(")?; @@ -507,10 +502,6 @@ fn type_tty( n += render(out, syn::PUNCTUATION)?; n += fmt::fprint(out, "}")?; case let f: ast::func_type => - if (f.attrs & ast::func_attrs::NORETURN != 0) { - n += render(out, syn::ATTRIBUTE)?; - n += fmt::fprint(out, "@noreturn ")?; - }; n += render(out, syn::TYPE)?; n += fmt::fprint(out, "fn")?; n += prototype_tty(out, indent, f)?; diff --git a/hare/ast/type.ha b/hare/ast/type.ha @@ -12,8 +12,9 @@ export type alias_type = struct { // A built-in primitive type (int, bool, str, etc). export type builtin_type = enum { - BOOL, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NULL, OPAQUE, - RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, VALIST, VOID, + BOOL, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NEVER, NULL, + OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, + VALIST, VOID, }; // An enumeration field (and optional value). @@ -37,12 +38,6 @@ export type variadism = enum { HARE, }; -// The attributes associated with a function type. -export type func_attrs = enum uint { - NONE = 0, - NORETURN = 1 << 0, -}; - // A parameter to a function type. export type func_param = struct { loc: lex::location, @@ -53,7 +48,6 @@ export type func_param = struct { // fn(foo: int, baz: int...) int export type func_type = struct { result: *_type, - attrs: func_attrs, variadism: variadism, params: []func_param, }; diff --git a/hare/lex/token.ha b/hare/lex/token.ha @@ -12,7 +12,6 @@ export type ltok = enum uint { ATTR_FINI, ATTR_INIT, - ATTR_NORETURN, ATTR_OFFSET, ATTR_PACKED, ATTR_SYMBOL, @@ -53,6 +52,7 @@ export type ltok = enum uint { LEN, LET, MATCH, + NEVER, NULL, NULLABLE, OFFSET, @@ -163,7 +163,6 @@ const bmap: [_]str = [ // Keep ordered with tok "@fini", "@init", - "@noreturn", "@offset", "@packed", "@symbol", @@ -204,6 +203,7 @@ const bmap: [_]str = [ "len", "let", "match", + "never", "null", "nullable", "offset", diff --git a/hare/parse/+test/loc.ha b/hare/parse/+test/loc.ha @@ -128,7 +128,7 @@ fn type_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { type_testloc("foo", "...foo"); type_testloc("int"); type_testloc("enum { FOO = bar }"); - type_testloc("fn(foo: bar) baz", "@noreturn fn(foo: bar) baz"); + type_testloc("fn(foo: bar) baz"); type_testloc("[foo]bar", "[*]foo", "[]foo", "[_]int"); type_testloc("*foo", "nullable *int"); type_testloc("struct { foo: bar }"); diff --git a/hare/parse/decl.ha b/hare/parse/decl.ha @@ -126,10 +126,10 @@ fn decl_type(lexer: *lex::lexer) ([]ast::decl_type | error) = { }; fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = { - let attr = ast::fndecl_attrs::NONE, noreturn = false, sym = ""; + let attr = ast::fndecl_attrs::NONE, sym = ""; const attrs = [ ltok::ATTR_FINI, ltok::ATTR_INIT, ltok::ATTR_TEST, - ltok::ATTR_NORETURN, ltok::ATTR_SYMBOL + ltok::ATTR_SYMBOL ]; for (true) match (try(lexer, attrs...)?) { case void => @@ -142,8 +142,6 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = { attr = ast::fndecl_attrs::INIT; case ltok::ATTR_TEST => attr = ast::fndecl_attrs::TEST; - case ltok::ATTR_NORETURN => - noreturn = true; case ltok::ATTR_SYMBOL => sym = attr_symbol(lexer)?; case => @@ -157,9 +155,6 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = { let proto_start = lex::mkloc(lexer); let prototype = prototype(lexer)?; let proto_end = lex::prevloc(lexer); - if (noreturn) { - prototype.attrs |= ast::func_attrs::NORETURN; - }; let tok = want(lexer, ltok::EQUAL, ltok::SEMICOLON)?; let body = switch (tok.0) { diff --git a/hare/parse/type.ha b/hare/parse/type.ha @@ -63,7 +63,6 @@ fn prototype(lexer: *lex::lexer) (ast::func_type | error) = { let t = _type(lexer)?; return ast::func_type { result = alloc(t), - attrs = ast::func_attrs::NONE, variadism = variadism, params = params, }; @@ -126,6 +125,8 @@ fn primitive_type(lexer: *lex::lexer) (ast::_type | error) = { yield builtin_type::VOID; case ltok::OPAQUE => yield builtin_type::OPAQUE; + case ltok::NEVER => + yield builtin_type::NEVER; case => return syntaxerr(lex::mkloc(lexer), "Unexected {}, was expecting primitive type", @@ -221,15 +222,8 @@ fn tuple_type( fn fn_type(lexer: *lex::lexer) (ast::_type | error) = { const start = lex::mkloc(lexer); - let attrs = match (try(lexer, ltok::ATTR_NORETURN)?) { - case void => - yield ast::func_attrs::NONE; - case => - yield ast::func_attrs::NORETURN; - }; want(lexer, ltok::FN)?; let proto = prototype(lexer)?; - proto.attrs |= attrs; return ast::_type { start = start, end = lex::prevloc(lexer), @@ -482,7 +476,7 @@ export fn _type(lexer: *lex::lexer) (ast::_type | error) = { ltok::U8, ltok::U16, ltok::U32, ltok::U64, ltok::INT, ltok::UINT, ltok::UINTPTR, ltok::SIZE, ltok::F32, ltok::F64, - ltok::VALIST, ltok::VOID, ltok::OPAQUE => + ltok::VALIST, ltok::VOID, ltok::OPAQUE, ltok::NEVER => yield primitive_type(lexer)?; case ltok::ENUM => yield enum_type(lexer)?; @@ -502,7 +496,7 @@ export fn _type(lexer: *lex::lexer) (ast::_type | error) = { yield tuple_type(lexer, t, tok.2)?; case => abort("unreachable"); }; - case ltok::ATTR_NORETURN, ltok::FN => + case ltok::FN => yield fn_type(lexer)?; case ltok::ELLIPSIS, ltok::NAME => yield alias_type(lexer)?; diff --git a/hare/types/+test.ha b/hare/types/+test.ha @@ -286,15 +286,14 @@ fn resolve( let st = store(x86_64, &resolve, null); defer store_free(st); - let atype = parse_type("@noreturn fn() void"); + let atype = parse_type("fn() never"); defer ast::type_finish(atype); let htype = lookup(st, &atype)!; assert(htype.sz == SIZE_UNDEFINED); assert(htype._align == SIZE_UNDEFINED); let f = htype.repr as func; - assert(f.result.repr as builtin == builtin::VOID); + assert(f.result.repr as builtin == builtin::NEVER); assert(f.variadism == variadism::NONE); - assert(f.flags == func_flag::NORETURN); assert(len(f.params) == 0); let atype = parse_type("fn(foo: int, bar: str...) int"); @@ -305,7 +304,6 @@ fn resolve( let f = htype.repr as func; assert(f.result.repr as builtin == builtin::INT); assert(f.variadism == variadism::HARE); - assert(f.flags == 0); assert(len(f.params) == 2); assert(f.params[0].repr as builtin == builtin::INT); assert(f.params[1].repr as builtin == builtin::STR); @@ -322,8 +320,8 @@ fn resolve( assert(htype._align == st.arch._int); let t = htype.repr as tagged; assert(len(t) == 2); - assert(t[0].repr as builtin == builtin::VOID); - assert(t[1].repr as builtin == builtin::INT); + assert(t[0].repr as builtin == builtin::INT); + assert(t[1].repr as builtin == builtin::VOID); let atype = parse_type("(int | (int | str | void))"); defer ast::type_finish(atype); @@ -332,9 +330,9 @@ fn resolve( assert(htype._align == 8); let t = htype.repr as tagged; assert(len(t) == 3); - assert(t[0].repr as builtin == builtin::VOID); + assert(t[0].repr as builtin == builtin::STR); assert(t[1].repr as builtin == builtin::INT); - assert(t[2].repr as builtin == builtin::STR); + assert(t[2].repr as builtin == builtin::VOID); }; @test fn alias() void = { diff --git a/hare/types/builtins.ha b/hare/types/builtins.ha @@ -64,7 +64,15 @@ export const builtin_i64: _type = _type { export const builtin_opaque: _type = _type { repr = builtin::OPAQUE, sz = SIZE_UNDEFINED, _align = SIZE_UNDEFINED, - id = 461893804, + id = 2374983655, + ... +}; + +// [[_type]] representation of never. +export const builtin_never: _type = _type { + repr = builtin::NEVER, + sz = SIZE_UNDEFINED, _align = SIZE_UNDEFINED, + id = 2374983655, ... }; @@ -72,7 +80,7 @@ export const builtin_opaque: _type = _type { export const builtin_rune: _type = _type { repr = builtin::RUNE, sz = 4, _align = 4, - id = 2374983655, + id = 1737287038, ... }; @@ -80,7 +88,7 @@ export const builtin_rune: _type = _type { export const builtin_u8: _type = _type { repr = builtin::U8, sz = 1, _align = 1, - id = 1906196061, + id = 1268499444, ... }; @@ -88,7 +96,7 @@ export const builtin_u8: _type = _type { export const builtin_u16: _type = _type { repr = builtin::U16, sz = 2, _align = 2, - id = 2206074632, + id = 4119164483, ... }; @@ -96,7 +104,7 @@ export const builtin_u16: _type = _type { export const builtin_u32: _type = _type { repr = builtin::U32, sz = 4, _align = 4, - id = 4119164483, + id = 3481467866, ... }; @@ -104,7 +112,7 @@ export const builtin_u32: _type = _type { export const builtin_u64: _type = _type { repr = builtin::U64, sz = 8, _align = 8, - id = 3481467866, + id = 1906196061, ... }; @@ -112,6 +120,6 @@ export const builtin_u64: _type = _type { export const builtin_void: _type = _type { repr = builtin::VOID, sz = 0, _align = 0, - id = 2543892678, + id = 3650376889, ... }; diff --git a/hare/types/hash.ha b/hare/types/hash.ha @@ -8,7 +8,7 @@ use strings; // Keep ordered with respect to bootstrap harec:include/types.h type storage = enum u8 { - BOOL, F32, F64, I16, I32, I64, I8, INT, NULL, OPAQUE, + BOOL, F32, F64, I16, I32, I64, I8, INT, NEVER, NULL, OPAQUE, RUNE, SIZE, STRING, U16, U32, U64, U8, UINT, UINTPTR, VOID, ALIAS, ARRAY, ENUM, FUNCTION, POINTER, SLICE, STRUCT, TAGGED, TUPLE, UNION, }; @@ -31,6 +31,8 @@ fn builtin_storage(b: builtin) u8 = { return storage::I8; case builtin::INT => return storage::INT; + case builtin::NEVER => + return storage::NEVER; case builtin::NULL => return storage::NULL; case builtin::OPAQUE => @@ -132,7 +134,6 @@ export fn hash(t: *_type) u32 = { case let f: func => write32(&id, hash(f.result)); write8(&id, f.variadism: u8); - write8(&id, f.flags: u8); for (let i = 0z; i < len(f.params); i += 1) { write32(&id, hash(f.params[i])); }; diff --git a/hare/types/store.ha b/hare/types/store.ha @@ -259,6 +259,10 @@ fn fromast(store: *typestore, atype: *ast::_type) (_type | deferred | error) = { sz = SIZE_UNDEFINED; _align = SIZE_UNDEFINED; yield builtin::OPAQUE; + case ast::builtin_type::NEVER => + sz = SIZE_UNDEFINED; + _align = SIZE_UNDEFINED; + yield builtin::NEVER; }; case let f: ast::func_type => yield func_from_ast(store, &f)?; @@ -358,12 +362,8 @@ fn func_from_ast( case ast::variadism::HARE => yield variadism::HARE; }, - flags = 0, params = alloc([], len(ft.params)), }; - if (ft.attrs & ast::func_attrs::NORETURN != 0) { - f.flags |= func_flag::NORETURN; - }; for (let i = 0z; i < len(ft.params); i += 1) { append(f.params, lookup(store, ft.params[i]._type)?); }; diff --git a/hare/types/types.ha b/hare/types/types.ha @@ -22,8 +22,9 @@ export type array = struct { export type builtin = enum u8 { // Keep me consistent with ast::builtin - BOOL, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NULL, OPAQUE, - RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, VALIST, VOID, + BOOL, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NEVER, NULL, + OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, + VALIST, VOID, }; // An enum type, e.g. enum { FOO = 0 } @@ -39,17 +40,10 @@ export type variadism = enum { HARE, }; -// Indicats if a [[func]] has the @noreturn attribute -export type func_flag = enum uint { - NONE = 0, - NORETURN = 1 << 0, -}; - // A function type, e.g. fn(x: int, y: int) int export type func = struct { result: const *_type, variadism: variadism, - flags: func_flag, params: []const *_type, }; diff --git a/hare/unparse/decl.ha b/hare/unparse/decl.ha @@ -87,9 +87,6 @@ export fn decl(out: io::handle, d: ast::decl) (size | io::error) = { yield "@test "; })?; let p = f.prototype.repr as ast::func_type; - if (p.attrs & ast::func_attrs::NORETURN != 0) { - n += fmt::fprint(out, "@noreturn ")?; - }; if (len(f.symbol) != 0) { n += fmt::fprintf(out, "@symbol(\"{}\") ", f.symbol)?; @@ -149,7 +146,6 @@ fn decl_test(d: ast::decl, expected: str) bool = { flags = 0, repr = ast::func_type { result = &type_int, - attrs = ast::func_attrs::NORETURN, variadism = ast::variadism::HARE, params = [ ast::func_param { @@ -235,11 +231,10 @@ fn decl_test(d: ast::decl, expected: str) bool = { body = void, attrs = ast::fndecl_attrs::FINI, }; - assert(decl_test(d, "@fini @noreturn @symbol(\"foo\") fn foo(foo: int, bar: int...) int;")); + assert(decl_test(d, "@fini @symbol(\"foo\") fn foo(foo: int, bar: int...) int;")); type_fn.repr = ast::func_type { result = &type_int, - attrs = 0, variadism = ast::variadism::NONE, params = [ ast::func_param { diff --git a/hare/unparse/type.ha b/hare/unparse/type.ha @@ -31,6 +31,8 @@ case ast::builtin_type::I8 => yield "i8"; case ast::builtin_type::INT => yield "int"; +case ast::builtin_type::NEVER => + yield "never"; case ast::builtin_type::NULL => yield "null"; case ast::builtin_type::OPAQUE => @@ -277,9 +279,6 @@ export fn _type( }; n += fmt::fprint(out, "}")?; case let f: ast::func_type => - if (f.attrs & ast::func_attrs::NORETURN != 0) { - n += fmt::fprint(out, "@noreturn ")?; - }; n += fmt::fprint(out, "fn")?; n += prototype(out, indent, f)?; case let l: ast::list_type => @@ -432,14 +431,12 @@ fn type_test(t: ast::_type, expected: str) void = { t.repr = ast::func_type { result = &type_int, - attrs = 0, variadism = variadism::NONE, params = [], }; type_test(t, "fn() int"); t.repr = ast::func_type { result = &type_int, - attrs = ast::func_attrs::NORETURN, variadism = variadism::C, params = [ ast::func_param { @@ -449,10 +446,9 @@ fn type_test(t: ast::_type, expected: str) void = { }, ], }; - type_test(t, "@noreturn fn(int, ...) int"); + type_test(t, "fn(int, ...) int"); t.repr = ast::func_type { result = &type_int, - attrs = 0, variadism = variadism::HARE, params = [ ast::func_param {